MySql:按商品数量然后按内容列出订单

时间:2019-01-04 18:05:35

标签: mysql sql group-by sql-order-by

我使用MySql 5.7,我需要对这样存储的列表进行排序:

| list_id | item   | item_index |
| ------- | ------ | ---------- |
| 0       | apple  | 0          |
| 0       | bread  | 1          |
| 1       | apple  | 0          |
| 1       | banana | 1          |
| 2       | orange | 0          |

但是这些项目不一定是字符串,它们可以是整数或布尔值,只是一种简化。

列表应按以下顺序排序:

  1. 列表中的项目数
  2. 如果两个列表的项目数相同,则应按item_index的顺序比较它们的项目

因此,此示例的结果应为:

  1. 2-橙色
  2. 1-苹果,香蕉
  3. 0-苹果,面包

我使用group bycount(*)按列表长度排序,但是问题是-如果列表中的最大项数未知,如何按列表内容排序?

我想出的唯一解决方案是在同一个表上进行N左连接,其中N是这个未知的最大列表长度,每个可能的列表项都进行了连接。请参阅表格以及我在DB Fiddle上对其进行排序的尝试。

有什么方法可以在不知道列表中最大项目数的情况下进行这种排序吗?

3 个答案:

答案 0 :(得分:3)

您可以先按count(*)然后按group_concat(item)进行排序,以按照列表的长度排序,然后通过比较项目:

select list_id, group_concat(item order by item_index asc) as items, count(*) as list_length
from yourtable
group by list_id
order by list_length asc, items asc

更新:

如果要订购数字,则group_concat()仍然有效,因为mysql隐式将数字转换为字符串。只需在数字的左边填充0即可确保正确排序,因为字符串比较19小于2。因此,按以下顺序更改group_concat(整数不能超过10位):

group_concat(LPAD(item, 10, '0') order by item_index asc)

答案 1 :(得分:2)

如果要从小提琴中取出5行,就像这样:

select * from 

  --the main data
  grocery_lists gl

  --joined with
  inner join

  --the count of items in each list
  (
    select list_id, group_concat(item order by item_index asc) as grouped_items, count(*) as total_count 
    from grocery_lists gl
    group by list_id
  ) ct
  on gl.list_id = ct.list_id

--ordered by the count of items, then the index 
order by ct.total_count, ct.grouped_items, gl.item_index

因此,您可以得到以下行:

   2, orange, 0  --sorts first because count - 1
   1, apple, 0   --sorts ahead of list 0 because "apple, banana" < "apple, bread"
   1, banana, 1
   0, apple, 0
   0, bread, 1

如果列表项是整数(并且您需要5行)

我认为您需要这样做:

select * from 

  --the main data
  grocery_lists gl

  --joined with
  inner join

  --the count of items in each list
  (
    select list_id, group_concat(LPAD(item, 10, '0') order by item_index asc) as grouped_items, count(*) as total_count 
    from grocery_lists gl
    group by list_id
  ) ct
  on gl.list_id = ct.list_id

--ordered by the count of items, then by padded aggregate ints, then index 
order by ct.total_count, ct.grouped_items, gl.item_index

如果您的项目是整数,则将它们填充到10宽(例如0)可以使排序有效,因为“ 0000000123,00000000124” <“ 0000000123,0000000125”

我选择了10个宽度,因为int max为45亿; 10位数字。如果您的整数较小,则可以减少填充

如果您比较布尔值(一种类似的策略),则可以将它们转换为INT(true = 0,false = 1?),以便它们正确排序(即使聚合为字符串也是如此)。

如果T,T,F的列表排在T,F,F的前面,则使T = 0和F = 1 ..例如

如果要从小提琴中取出三行。.

从Shadow借来,并针对item作为整数进行了调整:

select list_id, group_concat(item order by item_index asc) as items, count(*) as list_length
from yourtable
group by list_id
order by list_length asc, group_concat(LPAD(item, 8, '0') order by item_index asc) asc

答案 2 :(得分:0)

这是您想要的吗?我不确定订单

SELECT list_id,GROUP_CONCAT(item SEPARATOR ' ') aggregate_items ,SUM(item_index) aggregate_item_index 
FROM grocery_list
GROUP BY list_id
ORDER BY list_id DESC,COUNT(item) ASC,SUM(item_index) ASC