2009-11-19 147 views
10

我在设计购物车。为了避免旧产品发票在产品价格发生变化后显示不准确的问题,我将产品表中的价格字段转移到由3个字段(pid,日期和价格)组成的ProductPrice表中。 pid和日期形成表格的主键。这是一个什么样的表看起来像一个例子:SQL“GROUP BY”问题

pid date  price 
1  1/1/09 50 
1  2/1/09 55 
1  3/1/09 54 

使用SELECTGROUP BY找到最新的价格每一件产品,我想出了:

SELECT pid, price, max(date) FROM ProductPrice GROUP BY pid 

日期和PID回是准确的。每个独特的pid我只收到1个条目,并且伴随它的日期是该pid的最新日期。然而,令人惊讶的是价格回归。它返回的第一行的价格相匹配的PID,在这种情况下是50

返工我的发言后,我想出了这个:

SELECT pp.pid, pp.price, pp.date FROM ProductPrice AS pp 
INNER JOIN (
    SELECT pid AS lastPid, max(date) AS lastDate FROM ProductPrice GROUP BY pid 
) AS m 
ON pp.pid = lastPid AND pp.date = lastDate 

虽然返工语句现在产生正确的价格(54),似乎不可思议的是,这样一个简单的声音查询将需要一个内部联接来执行。我的问题是,我的第二个陈述是完成我需要做的最简单的方法吗?或者我在这里错过了什么?提前致谢!

詹姆斯

+0

简单,尽管仅在Postgresql上:SELECT DISTINCT ON(pid)pid,date,price FROM ProductPrice ORDER BY pid,date DESC – 2009-11-23 06:36:19

回答

9

你得到一个任意价格的原因是,mysql无法知道哪些列要选择,如果你GROUP BY东西。它知道它需要a价格和a每个pid的日期,并且可以根据您的要求获取最新日期max(date),但选择返回最有效的价格以供他检索 - 您没有为此提供aggregate function列(您的第一个查询实际上不是有效的SQL。)

你的第二个查询看起来不错,但这里是一个较短的选择:

SELECT pid, price, date 
FROM ProductPrice p 
WHERE date = (SELECT MAX(date) FROM ProductPrice tmp WHERE tmp.pid = p.pid) 

但是,如果你访问最新的价格很多(我认为你这样做),我会建议将旧列回如果您可以选择再次更改数据库结构,请将其保存到原始表中以保存最新值。

+0

其他DBMS会抱怨这个价格不包括为聚合或分组。 – 2009-11-19 09:49:37

+0

我必须认同这个更清洁。 – Zaid 2009-11-19 09:51:11

1

你可能会想试试这个:

SELECT pid, price, date FROM ProductPrice GROUP BY pid ORDER BY date DESC 

集团有一些不起眼的功能,我也一直不能确定,如果这是正确的领域...但它应该是第一在结果集中。

+0

这不起作用。它按降序排列生成的表格,而不是原始表格,因此不会选择最新的价格。 – Zaid 2009-11-19 09:48:30

3

我认为你打破了你的数据库模式。

为了规避旧的发票显示产品的价格后定价不准确的问题得到改变,我搬到从产品表中的价格字段成由3个领域,PID,日期和价格的ProductPrice表。 pid和日期形成表格的主键。

正如您已经指出,您需要保持价格的变化历史。但是除了新表之外,您仍然可以在产品表中保留当前价格。这会让你的生活更轻松(而且你的查询更快)。

0

这里是另一个 - 可能缺乏效率的一个:

SELECT pid, substring_index(group_concat(price order by date desc), ',', 1) , max(date) 
    FROM ProductPrice 
GROUP BY pid 
0

我认为,这里的关键是简单冠冕堂皇查询 - 你可以看到你想要什么,但电脑是不是人,因此产生基于集合的操作所需的结果必须与第二个查询中一样明确。

内部查询标识的最后价格为每个产品,再查询外层的让你得到的价值在过去的价格 - 这是因为它可以得到一样简单。另外,如果您有开票系统,您确实应该在发票上存储产品的价格(以及税率以及“代码”),即发票表应该包含所有必要的财务信息来重现发票。一般情况下,你想依靠的是能够查找一个价格(或税率)的可变表甚至允许如上面介绍的系统。无论如何,定价历史都有其优点。

1

不能与集团解决您的问题BY子句,因为每个组PID的MySQL简单地获取第一PID,最大日期和发现的第一个价格(这是不是你所需要的)。

您既可以使用子查询(可以是低效):

SELECT pid, date, price 
FROM ProductPrice p1 
WHERE date = (SELECT MAX(p2.date) 
       FROM ProductPrice p2 
       WHERE p1.pid = p2.pid) 

,或者你可以简单地加入表本身:

SELECT p1.pid, p1.date, p1.price 
FROM  ProductPrice p1 
LEFT JOIN ProductPrice p2 ON p1.pid = p2.pid 
      AND p1.date < p2.date 
WHERE  p2.pid IS NULL 

看看MySQL的文档的this section

0

我面临同样的问题,在我的项目,我用子查询来获取日期,然后比较它的一个,但它使系统缓慢的数据增加时。因此,除了您创建的新表格以保留价格变化的历史记录之外,最好将“最新价格”存储在“产品”表格中。

你可以随时使用任何查询PPL的建议,以获得最新的价格在特定日期的产品。但也可以在同一张表中添加一个字段。所以对于一个日期,你可以使旗帜真实一次。您可以通过一个简单的查询随时查找特定日期的产品最新价格。