我使用MySql 5.7,我需要对这样存储的列表进行排序:
| list_id | item | item_index |
| ------- | ------ | ---------- |
| 0 | apple | 0 |
| 0 | bread | 1 |
| 1 | apple | 0 |
| 1 | banana | 1 |
| 2 | orange | 0 |
但是这些项目不一定是字符串,它们可以是整数或布尔值,只是一种简化。
列表应按以下顺序排序:
因此,此示例的结果应为:
我使用group by
和count(*)
按列表长度排序,但是问题是-如果列表中的最大项数未知,如何按列表内容排序?
我想出的唯一解决方案是在同一个表上进行N
左连接,其中N
是这个未知的最大列表长度,每个可能的列表项都进行了连接。请参阅表格以及我在DB Fiddle上对其进行排序的尝试。
有什么方法可以在不知道列表中最大项目数的情况下进行这种排序吗?
答案 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)
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
我认为您需要这样做:
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