MySql:先按项目数再按内容排序列表

MySql: order lists by number of items and then by content

我使用 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
  3. 的顺序比较它们的项

所以这个例子的结果应该是:

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

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

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

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

像这样,如果您想要 fiddle 中的 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

如果您的项目是整数,用 0 将它们填充到例如 10 宽会使排序有效,因为 "0000000123, 00000000124" < "0000000123, 0000000125"

我选了10宽因为int max是45亿; 10 位数字。如果你的整数会更小,你可以少填充

如果您要比较布尔值,这是一种类似的策略,也许可以将它们转换为 INT(true=0,false=1?),这样它们就会正确排序,即使聚合成一个字符串也是如此..

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

如果您想要 fiddle..

中的 3 行

从 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

您可以按 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)

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

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