计算 SQLite 中 group_concat 聚合后的唯一行数

Posted

技术标签:

【中文标题】计算 SQLite 中 group_concat 聚合后的唯一行数【英文标题】:Count the number of unique rows after a group_concat aggregate in SQLite 【发布时间】:2017-06-04 21:45:30 【问题描述】:

在仔细阅读 this answer about *** vs dba.se 后,我在 *** 上提出了这个问题——我是一个非专家数据库新手,在我可能被误导的估计中,一个非 DBA 编码人员可以像数据库专家一样帮助我。 SQLite 也是一个“精简”数据库。

我的 SQLite 表用于,比如说,食谱场景。它有两列:每一行都有一个字段,meal 和一个 ingredient 用餐所需的字段。由于大多数餐点使用不止一种成分,因此有许多行具有相同的meal 但不同的ingredients。

我需要知道确切的配料组可以做多少餐——实际上我需要一份所有配料的分类清单,以及用这些配料可以做多少餐。我希望代码能完全解释这一点:

CREATE TABLE recipes (
      meal TEXT,
      ingredient TEXT);

INSERT INTO recipes VALUES
  ("tandoori chicken","chicken"), ("tandoori chicken","spices"),
  ("mom's chicken","chicken"), ("mom's chicken","spices"),
  ("spicy chicken","chicken"), ("spicy chicken","spices"),

  ("parmesan chicken","chicken"), ("parmesan chicken","cheese"), ("parmesan chicken","bread"),
  ("breaded chicken","chicken"), ("breaded chicken","cheese"), ("breaded chicken","bread"),

  ("plain chicken","chicken");

这里有

一套三餐,使用完全相同的食材(唐杜里鸡、妈妈鸡和麻辣鸡), 另一组 餐,使用一组不同的食材,并且 一餐另一餐完全需要其成分。

我想要类似下面的东西:

chicken,,,spices|3
chicken,,,cheese,,,bread|2
chicken|1

也就是说,一个字符串包含确切的成分集以及使用这些成分可以制作多少餐。 (不用担心对食材进行整理/分类,我可以确保每顿饭,行将始终以相同的顺序插入。另外,不用担心相同的病理情况meal-@987654330 @ 行重复——我可以防止这种情况发生。)

我可以像这样得到上面的输出:

  WITH t
       AS (SELECT group_concat(recipes.ingredient, ",,,") AS ingredients
           FROM   recipes
           GROUP  BY recipes.meal)
  SELECT t.ingredients,
         count(t.ingredients) AS cnt
  FROM   t
  GROUP  BY t.ingredients
  ORDER  BY cnt DESC;

我对此不满意有几个原因:首先,它创建了一个子视图,我真的很好奇是否有一种方法可以在没有子视图的情况下实现这一点——这可能会更快、更清晰.其次,在子视图中,我通过group_concat 创建了一个字符串 来表示成分向量——我觉得应该有一个基于行的或数据结构 类似,从 SQL 中获取相同信息的方法。

我的问题:我能否在不使用子视图和/或不使用字符串连接的情况下获得上述输出或类似的输出?

【问题讨论】:

如果这样的查询甚至可以在没有子选择的情况下进行(可能有很多丑陋的自连接假设最大数量的可能成分?嗯)我认为这将更难理解。Sub-查询在 SQL 中很正常,我真的不明白为什么有人想要避免它们。我的意见是先编码清楚,如果速度不够快,然后再重写。此外,只要使用在数据中不可能出现的分隔符,我认为 group_concat 没有任何问题。我想你的三个逗号就是这种情况。 【参考方案1】:

这种简化似乎有效:

SELECT distinct  group_concat(recipes.ingredient, ",,,")
     , count(*) AS cnt
FROM      recipes recipes
GROUP  BY recipes.meal 
ORDER  BY cnt DESC;

这实际上只是对已有内容的重新表述,没有嵌套查询或公用表表达式。

由于配方可以包含任意数量的成分,因此重复连接是不可行的(没有递归),所以我认为这是 GROUP_CONCAT() 函数多么方便的一个很好的例子。

编辑: 哎呀,你是对的,对此感到抱歉。再看问题,我认为需要单独的结果集。有 2 个级别的聚合,一个用于“透视”数据,因此它是带有每个成分列表的配方颗粒,然后另一个用于计算具有相同成分列表的配方数量。下面是一个简单的查看方式,使用 GROUP_CONCAT 中的 'order by' 来控制排序,因此将相同的成分列表分组在一起。 -

select ingredients_list, count(*) from (     SELECT meal, group_concat(recipes.ingredient, ",,," order by recipes.ingredient) as ingredients_list FROM recipes recipes GROUP BY recipes.meal ) meal_ingredients group by ingredients_list ; 

【讨论】:

Doh,毕竟我需要一个子视图,因为group_concat 的顺序是任意的,所以成分可能会在结果字符串中随机排列? per ***.com/q/1897352/500207 ... Doh—Vince,这实际上是行不通的。 cntgroup_concatted 元素的数量,不是结果出现的频率。将我的原始输出 chicken,,,spices|3chicken,,,cheese,,,bread|2 与您的代码输出进行比较:chicken,,,cheese,,,bread|3chicken,,,spices|2——这些数字意味着不同的东西。有什么建议吗? 糟糕,你是对的,对此感到抱歉。再看问题,我认为需要单独的结果集。有 2 个级别的聚合,一个用于“透视”数据,因此它是带有每个成分列表的配方颗粒,然后另一个用于计算具有相同成分列表的配方数量。下面是一个简单的查看方式,在 GROUP_CONCAT 中使用 'order by' 来控制排序,因此将相同的成分列表分组在一起。 选择成​​分列表,计数(*)来自(选择餐,组连接(recipes.ingredient,“,,,”按recipes.ingredient排序)作为成分列表从食谱食谱组按食谱组)膳食成分组按成分列表; 你可以用这个来编辑你的答案吗?然后我会将其标记为已接受:)!

以上是关于计算 SQLite 中 group_concat 聚合后的唯一行数的主要内容,如果未能解决你的问题,请参考以下文章

查询中 group_concat 上的 SQLITE 不需要的行为

在 SQLite 的 GROUP_CONCAT 函数中使用 ORDER BY 子句

在 SQLite 中,多个列的排序方式是不是与 group_concat 相同?

group_concat 以及如何在 sqlite 中使用行号

group_concat sqlite 和 order by

SQLite - 是不是可以在同一个查询中使用 group_concat 函数但 'GROUP BY' 不同的标准?