【问题标题】:MySql: order lists by number of items and then by contentMySql:按项目数量然后按内容排序列表
【发布时间】:2019-05-31 07:46:27
【问题描述】:

我使用 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 上对其进行排序的尝试。

有没有办法在不知道列表中最大项目数量的情况下以这种方式对其进行排序?

【问题讨论】:

  • 列表的“长度”是指“列表中项目数量的升序”
  • 我无法弄清楚这个问题试图完成什么,或者“长度”是什么,因为表中没有长度度量或称为长度的字段。 - 啊,我现在明白了。给定 list_id 的所有项目都是同一个列表。您首先想要最大的列表(依此类推),然后在每个列表中按顺序排列每个列表的项目(按索引)。
  • 是的,是项目数,“列表中项目数的升序”,我来编辑一下
  • 通过“如果项目数相同,则应按照 item_index 的顺序比较项目 - 0 与 0 等”您的意思是“如果两个列表的项目数相同,那么listitems 应按 itemindex 的顺序进行比较,并使用字母顺序来决定哪个列表在前)"
  • 我也不太清楚你是否想要逐行(希望得到 5 行的结果?)或者你想要一个分组/聚合集(唯一列表 ID,一列N个列表项,输出3行)

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


【解决方案1】:

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

【讨论】:

  • 对不起,我错过了重要的一点——这些项目不一定是字符串,它们也可能是整数。我无法聚合它们,它们应该相互比较
  • @NadezhdaRatskevich Mysql 不是电子表格工具,你不能在一个列中有不同的数据类型。
  • 当然,它们都具有相同的类型,但我需要的解决方案也适用于另一个具有整数/布尔项的表,例如 db-fiddle.com/f/aVEhJ29gP1CRgRbG5Q9WzP/1
  • 我认为这与您在 mysql 中的合理程度一样接近。如果数据不是字符串,请将其转换并填充,使其正确排序 - 请参阅我对答案所做的编辑
【解决方案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"

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

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

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

如果您想从小提琴中取出 3 行..

从 Shadow 中借用,并为 item 调整为 int:

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

【讨论】:

    【解决方案3】:

    这是你想要的吗?我不确定顺序

    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
    

    【讨论】:

    • 对不起,我忘了说如果项目是整数或布尔值,它也应该工作,就像这张表db-fiddle.com/f/aVEhJ29gP1CRgRbG5Q9WzP/1
    • 它有效。 GROUP_CONCAT 使用整数和布尔值。
    • 是的,它不会失败,但是由于字符串比较,2会被认为大于19。
    • 按顺序排列的列是count,而不是group_concat
    • 现在可以了吗? group by 子句中的列不必在显示的列中。
    猜你喜欢
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 2011-11-22
    • 2010-12-14
    相关资源
    最近更新 更多