【问题标题】:Group items by 2 columns or similarity with another column按 2 列或与另一列的相似性对项目进行分组
【发布时间】:2021-09-20 23:59:29
【问题描述】:

假设我们有一个 Sqlite 表,其中包含:

name;city;age;id;foo
Alice;New-York;25;13782749;12
Eve;Chicago;23;1938679;34
Bob;New-York;25;824697624;56
Jack;Denver;30;239679163;12
Simone;Denver;30;1687631;99

如何按h=CONCAT(city,age) 分组同时在组中添加与组中某人具有相同foo 列的用户?

Group items by 2 columns 中所见,这里是如何按h 分组:

select dense_rank() over (order by city, age) as grpnum, name, id from t;

如何在foo 上添加第二个条件?

示例:这里 Alice 和 Bob 在同一个 group1 中,因为他们有相同的 h=CONCAT(city,age),但是 Jack 应该在 group1 中,因为他与 Alice 具有相同的 foo 值:@ 987654331@。 Simone 的CONCAT(city,age) 与 Jack 相同,因此她与 Jack 属于同一组,在 group1 中也是如此。

【问题讨论】:

  • 如果有另一个来自丹佛的 30 岁的人,他们会在自己的小组中吗?还是和杰克一起?
  • @GordonLinoff 与杰克和其他人在一起。如果foo 相似,则将它们组合在一起。
  • @GordonLinoff 我在另一个用户 Simone 的问题中添加了一个示例。

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


【解决方案1】:

这要棘手得多。这是一个graph-walking问题,需要递归CTE(Common Table Expression)。

这个想法是生成名称之间的所有边。然后使用递归 CTE 访问所有连接的节点 (names),避免访问现有节点。

这是一种方法:

with recursive edges as (
      select distinct t1.name as name1, t2.name as name2
      from t t1 join
           t t2
           on t1.city = t2.city and t1.age = t2.age or
              t1.foo = t2.foo
     ),
     cte as (
      select name1, name2, min(name1, name2) as first_name,
             ',' || name1 || ',' || name2 || ',' as visited
      from edges
      union all
      select cte.name1, e.name2, min(cte.first_name, e.name2),
             visited || e.name2 || ','
      from cte join
           edges e
           on e.name1 = cte.name2
      where visited not like '%,' || e.name2 || ',%'
     )
select t.*, cte.grpnum
from t join
     (select name1, min(first_name), dense_rank() over (order by min(first_name)) as grpnum
      from cte
      group by name1
     ) cte
     on t.name = cte.name1;

here 是一个数据库小提琴。

【讨论】:

  • 非常感谢 Gordon,我将深入研究它以了解其工作原理。
猜你喜欢
  • 2021-11-14
  • 2015-02-23
  • 2020-05-26
  • 1970-01-01
  • 2014-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-19
相关资源
最近更新 更多