查询列出每个订单项,但只列出一次总计

时间:2018-06-19 07:44:59

标签: sql postgresql

我们有一个销售报告,从多个表中提取数据,我的查询显示正确的数据,但具有多个订单项的订单除外,即每个订单项行上都列出了订单总计。

如何在具有最小订单项ID(对于该订单)但仍列出每个订单项行的行上仅列出订单总计一次?谢谢!

数据结构:

订单表:

  • Order_ID上

订单项表:

  • ID
  • Order_ID上
  • Line_Item_Price
  • Line_Item_Qty

结果应该是:

  Order_ID   Total   Line_Item_Price   Line_item_Qty   Line_Item_ID  
 ---------- ------- ----------------- --------------- -------------- 
     10001     200               100               2          32001  
     10002     150               150               1          32002  
     10003     210                55               1          32003  
     10003                        30               2          32004  
     10003                        95               1          32005  
     10004     125               125               1          32006  

2 个答案:

答案 0 :(得分:1)

这应该在不在SQL中的应用程序中完成。

但是你可以使用window functions 来做到这一点

select o.order_id, 
       case row_number() over (partition by o.order_id order by line_item_id)
         when 1 then o.total
       end as total, 
       li.line_item_price,
       li.line_item_qty,
       li.line_item_id
from orders o 
  join line_item li on o.order_id = li.order_id
order by o.order_id, li.line_item_id;

row_number()为每个订单的每个订单项分配一个唯一的行号。当数字为1时,显示总数,否则不显示。

在关系数据库中除非您指定order by,否则不存在“第一行” - 在这种情况下,“第一行”是具有最小line_item_id的订单项

在线示例:http://rextester.com/TQOIX50171

不相关,但是:将总数存储在orders表中并不是一个非常好的主意。在标准化设计中,您不应存储可从现有数据轻松派生的信息。

答案 1 :(得分:0)

这样做是通过他们的物品获得订单并对其进行排名。因此,最小的item_id是该订单的等级1,最新的是最后的等级。

ROW_NUMBER()是给出查询输出中行的索引的函数(第1行= 1,第2行= 2)。然后我们可以将它与OVER(PARTITION BY)结合起来,这意味着获取某个窗口内的行号,一个分区。在这种情况下,我们想要为Order_IDs的窗口编号行。我们一起使用ORDER BY来说明我们如何在窗口中对行进行排序

当我们有这个表时,我们可以在其上写一个查询,只显示item_rank = 1

的行的总数
WITH rank_items_for_orders AS (
   SELECT
          Order_ID,
          Line_Item_Price,
          Line_Item_Qty,
          Line_Item_ID,
          Total,
          ROW_NUMBER() 
     OVER (PARTITION BY Order_ID, ORDER BY Line_Item_ID ASC) 
       AS order_the_items_IDs
     FROM orders o
LEFT JOIN line_items li ON o.order_id = li.order_id
 ORDER BY Order_ID ASC)

SELECT
       Order_ID,
       Line_Item_Price,
       Line_Item_Qty,
       Line_Item_ID,
      CASE WHEN order_the_items_IDs = 1 
      THEN Total ELSE NULL END 
        AS Total
FROM
rank_items_for_orders