【问题标题】:Group records based on two columns with possible chains基于具有可能链的两列对记录进行分组
【发布时间】:2018-12-06 16:46:47
【问题描述】:

我正在使用 PostgreSQL,但我对 SQL 却一无所知。我有一个很长的记录表,并希望将它们分配到组中,其中组的每个成员具有与组中至少一个其他成员相同的两列之一。理想情况下,通过创建一个表格,其中包含来自任一列的所有不同值(那里没有重叠,因为它们是完全不同的字符值)以及它们所属的组数。

我希望某些组仅由一个成员组成,但可能存在很长的关系链,其中两条记录未连接,但第三条记录将它们连接起来。使用编程语言(例如 JavaScript)我可能会使用递归函数,但使用 SQL 我会迷路。

我曾尝试寻找答案,但我发现很难找到合适的关键词。这有点像一个巨大的多米诺骨牌游戏,但仍然有点不同。这个问题有什么简单的解决方案吗?如果没有,有人可以指点我一个好的方向吗?

编辑: 一些示例数据。 userId 和 session 是我的两列。所以在这种情况下,Id 2、4 和 6 将在同一个组中。

Id 类型 userID 会话 1 回调 25596094 lJcD7fiFCnB4o4ZxI_DQHKMmBGW1T0b4 2 回调 26631605 xupFcU6C8cl7wdviOnc1XX37Feg234vK 3 回调 02-9128924-01 eNE8VuJBz9vffGeuALy72owq1cJhK84l 4 回调 26631605 GhenxfiVXQaGbYq2_SXJhhkvTRN8M3vb 5 回调globetrotter-394146 PdJEDeW57piXMu6nNsJjLZeFmNrP2jvG 6 回调 31831125 xupFcU6C8cl7wdviOnc1XX37Feg234vK

【问题讨论】:

  • 递归查询可以轻松地从起始行获取所有相关行,并将相同的“组 ID”分配给所有找到的行。现在,您需要多次运行它才能无限地处理第二、第三、第四组。
  • 请添加一些示例数据,便于我们了解具体情况。几行就足够了。

标签: sql postgresql


【解决方案1】:

这只是一个部分解决方案,它将根据您的逻辑检索与第一行“相关”的所有行。

在这种情况下,如果我们从行 (id = 4) 开始,查询可能是:

with recursive
x as (
  select * from my_table where id = 4 -- this is the starting row
  union all
  select t.* 
  from my_table t
  join x on t.userID = x.userId or t.session = x.session
)
select * from x

结果将是:

Id   Type      userID                session
4    callback  26631605              GhenxfiVXQaGbYq2_SXJhhkvTRN8M3vb
2    callback  26631605              xupFcU6C8cl7wdviOnc1XX37Feg234vK
6    callback  31831125              xupFcU6C8cl7wdviOnc1XX37Feg234vK

查询需要更多的工作才能使其对所有行运行,而不仅仅是像这种情况下的子集。

2018 年 12 月 7 日更新:

我编写了一个 SQL 更新,它将找到 one 组并为其分配一个新的(不同的)group_id 值。如果您多次运行此 SQL 更新,您最终会将组 ID 分配给所有行。这里是:

alter table my_table add group_id int; -- extra column stores the group_id

create sequence group_id_seq; -- will generate a different group_id each time

with recursive
s as (
  select nextval('group_id_seq') as nv
),
x as (
  select * from (
    select * from my_table where group_id is null fetch first 1 rows only
  ) x
  union
  select t.*
  from my_table t
  join x on t.userid = x.userid or t.session = x.session
)
update my_table t set group_id = s.nv from s, x where t.id = x.id;

同样,每次运行它时,它都会用新的组 id 值标记一组新的 [未标记] 行。

希望对你有帮助。

【讨论】:

  • 这不是一遍又一遍地选择同一行吗?当我运行类似的东西时,它需要很长时间并多次返回同一行。我将“union all”改为“union”,看起来更好。
  • 是的,它只是在进行中。为了选择新的,您需要“标记”已经拍摄的。也许您可以添加一个名为 group_id 的额外列,该列最初为 null,并填充了来自序列的新组 id。另一件事是,起点(id = 4)可能应该来自一个查询,该查询获取任何(只有一个)随机行形式,其中group_id 为空。让我一会儿试试。
  • 请试用我写的UPDATE。这让我的兴趣达到了顶峰。让我知道它是否有效。
  • 效果很好!我将它放在一个函数中并循环它,直到 group_id 中没有空值。非常感谢!永远不会想出如此紧凑的解决方案。
猜你喜欢
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 2021-10-06
  • 2017-03-09
  • 2018-09-01
  • 2013-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多