Postgresql SELECT DISTINCT ON

时间:2014-04-23 22:51:35

标签: sql postgresql

在下面的查询中,我尝试选择数据,但需要在Book.Title和OrderDate列上区分数据。我已经尝试过使用DISTINCT ON,但也会得到多个结果,我将在下面发布。对不起,如果问题有点微不足道。我目前正在学习SQL,所以当涉及到我可能错过的非常明显的东西时,我有点像菜鸟。

如何更改查询以将结果格式化为:

   month   |                    title                    | quantity | total_value 
-----------+---------------------------------------------+----------+-------------
 February  | Internet and World Wide Web: How to Program |       15 |      899.70
 March     | C How To Program                            |        4 |      183.92
 March     | Core Servlets and JavaServer Pages          |       13 |      856.70
 March     | Internet and World Wide Web: How to Program |       21 |     1071.58

我构建的查询:

SELECT DISTINCT ON (OrderDate, Book.Title) Book.Title, to_char(OrderDate, 'Month') AS "Order Date", 
OrderLine.Quantity AS "Order Quantity", (SUM(Quantity*UnitSellingPrice)) AS "Total Value"
FROM Book
INNER JOIN Publisher
ON Book.PublisherID=Publisher.PublisherID
INNER JOIN OrderLine
ON Book.BookID=OrderLine.BookID
INNER JOIN ShopOrder
ON OrderLine.ShopOrderID=ShopOrder.ShopOrderID
WHERE Publisher.Name='Prentice Hall'
GROUP BY book.title, OrderDate, orderline.quantity
ORDER BY OrderDate ASC;

我得到的结果:

                    title                    | Order Date | Order Quantity | Total Value 
---------------------------------------------+------------+----------------+-------------
 Internet and World Wide Web: How to Program | February   |             10 |      299.90
 Internet and World Wide Web: How to Program | February   |              5 |      149.95
 C How To Program                            | March      |              3 |       68.97
 Core Servlets and JavaServer Pages          | March      |             10 |      329.50
 Internet and World Wide Web: How to Program | March      |             20 |      519.80
 C How To Program                            | March      |              1 |       22.99
 Core Servlets and JavaServer Pages          | March      |              3 |       98.85
 Internet and World Wide Web: How to Program | March      |              1 |       15.99

非常感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

我认为您在这里过于复杂:如果您想要每个标题和月份的总数量,那么您希望分组标题和月份,并且总和数量。您 希望分组数量本身,因为这意味着每个不同数量的新行。

在标准SQL中很容易做到(DISTINCT ON是一个Postgres扩展,在少数情况下很有用而不是 GROUP BY,但这里不必要):

SELECT
    Book.Title,
    to_char(OrderDate, 'Month') AS "Order Date", 
    SUM(OrderLine.Quantity) AS "Order Quantity", 
    SUM(Quantity*UnitSellingPrice) AS "Total Value"
FROM [...]
WHERE Publisher.Name='Prentice Hall'
GROUP BY
    book.title,
    to_char(OrderDate, 'Month')
ORDER BY to_char(OrderDate, 'Month') ASC;

经验法则是SELECT条款中的所有内容 - 以及ORDER BY条款,它被认为是"在同一级别" - 应该是:

  • GROUP BY子句中列出,因为每次变化都需要新行
  • 或包含在聚合函数(此处为SUM())中,因为您希望"将其卷起来#34;根据一些规则。

答案 1 :(得分:1)

要了解发生了什么,请考虑:

SELECT DISTINCT ON (OrderDate, Book.Title)
    Book.Title,
    OrderDate as "Actual Order Date",
    to_char(OrderDate, 'Month') AS "Order Month", ..

也就是说,帖子中的结果选择不同的“订单日期”,实际上是订单月份,但不是实际的 OrderDate值使用的在DISTINCT / GROUP BY过程中,它解释了重复和不正确的聚合结果。

我怀疑所需的查询类似于以下内容,我还没有发现需要在GROUP BY中使用DISTINCT。

SELECT
  -- These are in the GROUP BY and will be DISTINCT in the result
  Book.Title,
  to_char(OrderDate, 'Month') AS "Order Month", 
  -- Non GROUP BY values should be aggregated;
  -- In this case the aggregates are over Title/Month
  SUM(OrderLine.Quantity) AS "Order Quantity",
  SUM(Quantity*UnitSellingPrice) AS "Total Value"
FROM Book
INNER JOIN Publisher
ON Book.PublisherID=Publisher.PublisherID
INNER JOIN OrderLine
ON Book.BookID=OrderLine.BookID
INNER JOIN ShopOrder
ON OrderLine.ShopOrderID=ShopOrder.ShopOrderID
WHERE Publisher.Name='Prentice Hall'
-- For each Title/Month
GROUP BY book.title,
         to_char(OrderDate, 'Month')       -- also grouped on Month
ORDER BY to_char(OrderDate, 'Month') ASC;  -- and sorted on Month