在SQL中排序时如何保留逻辑分组?

时间:2013-11-12 18:11:32

标签: mysql sql postgresql sorting

我有两个与父子关系相关的表

Sale
sale_id | customer_name

SaleItem
item_id | sale_id | item_type

每个销售记录都有一个或多个相应的SaleItem记录。我的目标是创建一个Sales列表,其相应的SaleItems显示为子项。我可以使用此查询执行此操作:

SELECT s.sale_id, s.customer_name, si.item_id, si.item_type 
FROM Sale s, SaleItem si
WHERE s.sale_id=si.sale_id
ORDER BY s.sale_id, si.item_id

产生类似这样的东西(为了清楚问题,添加了空白行):

sale_id | customer_name | item_id | item_type
1       | Sam           | 1       | D
1       | Sam           | 2       | B
1       | Sam           | 3       | D

2       | Nate          | 4       | A
2       | Nate          | 5       | B

3       | Mike          | 6       | B
3       | Mike          | 7       | C

4       | Nate          | 8       | C
4       | Nate          | 9       | D

ORDER BY子句导致Sales与其有序SaleItems的逻辑分组。这为我提供了能够编写一个漂亮的可折叠UI来表示数据所需的数据:

-Sale 1 - Sam
 -B 
 -B 
 -D 
+Sale 2 - Nate
+Sale 3 - Mike
-Sale 4 - Nate
 -C
 -D

这一切都很好,但是当我想按item_type对此列表进行排序时会发生什么?我想最终得到这样的结果集(为了清楚问题,添加了空白行):

sale_id | customer_name | item_id | item_type
2       | Nate          | 4       | A
2       | Nate          | 5       | B

3       | Mike          | 6       | B
3       | Mike          | 7       | C

4       | Nate          | 8       | C
4       | Nate          | 9       | D

1       | Sam           | 1       | D
1       | Sam           | 2       | B
1       | Sam           | 3       | D

请注意,每个销售及其相应的SaleItems保持在一起。基本上我需要做的是将每组Sale + SaleItems作为单个元素处理,并按任意列智能地对它们进行排序。由于我们实际上只是在这里对Sales进行排序,而item_type适用于SaleItem,我们只需按第一个SaleItem的item_type排序,并维护Sale中SaleItems的原始排序顺序。我真的希望这是有道理的。

我有几个问题:

  1. 我是以错误的方式来做这件事的吗?由于每个Sale记录都是一个或多个SaleItem记录的“父”,因此JOIN似乎有点过分,因为我最终会在每个“子”行中复制“父”数据。
  2. 如何按每个销售的第一个item_type对此数据进行排序,并将每个Sale的SaleItem保持在一起?
  3. 非常感谢。

1 个答案:

答案 0 :(得分:0)

尝试这样的事情:

SELECT s.sale_id, 
       s.customer_name, 
       si.item_id, 
       si.item_type,
       min(si.item_type) OVER (PARTITION BY sale_id) as min_item_type
FROM Sale s, SaleItem si
WHERE s.sale_id=si.sale_id
ORDER BY min_item_type, s.sale_id, si.item_id

它会给你的结果接近你所展示的例子。

您可以将min(si.item_type)替换为任何窗口函数(例如,maxfirstlast ...)以获取item_type, "描述"每个sale_id组。