SQL“GROUP BY”问题

时间:2009-11-19 09:32:09

标签: sql select mysql group-by

我正在设计购物车。为了避免在产品价格发生变化后显示不准确定价的旧发票问题,我将价格字段从Product表移动到ProductPrice表中,该表包含3个字段,pid,日期和价格。 pid和date构成表的主键。这是表格的示例:

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),但这样一个简单的声音查询需要内部联接才能执行似乎令人难以置信。我的问题是,我的第二个陈述是完成我需要做的最简单的方法吗?或者我在这里遗漏了什么?提前谢谢!

詹姆斯

7 个答案:

答案 0 :(得分:9)

您获得任意价格的原因是,如果您GROUP BY某事,mysql无法知道要选择哪些列。它知道每个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)

但是如果您经常访问最新价格(我认为您这样做),我建议您将旧列添加回原始表以保留最新值,如果您可以选择再次更改数据库结构。

答案 1 :(得分:3)

我认为你打破了数据库架构。

  

为了避免在产品价格发生变化后显示价格不准确的旧发票问题,我将价格字段从Product表移动到ProductPrice表中,该表包含3个字段,pid,日期和价格。 pid和date构成表的主键。

正如您所指出的,您需要保留价格的变化记录。但除了新表之外,您仍然可以将当前价格保留在products表中。这将使您的生活更轻松(并且您的查询更快)。

答案 2 :(得分:1)

你可能想试试这个:

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

Group有一些不起眼的功能,我总是不确定它是否是正确的字段......但它应该是结果集中的第一个。

答案 3 :(得分:1)

使用GROUP 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

答案 4 :(得分:0)

这是另一个 - 效率低下的一个:

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

答案 5 :(得分:0)

我认为这里的关键是简单的听起来查询 - 您可以看到您想要的但计算机不是人类,因此要从基于集合的操作中产生所需的结果,您必须明确表示在第二个查询中。

内部查询标识每个产品的最后价格,然后外部查询可以让您获得最后价格的价值 - 这就像它可以获得的那样简单。

顺便说一句,如果你有一个发票系统,你真的应该把产品的价格(和税率以及“代码”)与发票一起存储,即发票表应该包含所有必要的财务重现发票的信息。一般而言,您希望依赖于能够在可变表中查找价格(或税率),甚至允许如上所述引入的系统。无论如何,定价历史都有其自身的优点。

答案 6 :(得分:0)

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

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