根据带有可能链的两列对记录进行分组

时间:2018-12-06 16:46:48

标签: sql postgresql

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

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

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

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

Id   Type      userID                session
1    callback  25596094              lJcD7fiFCnB4o4ZxI_DQHKMmBGW1T0b4
2    callback  26631605              xupFcU6C8cl7wdviOnc1XX37Feg234vK
3    callback  02-9128924-01         eNE8VuJBz9vffGeuALy72owq1cJhK84l
4    callback  26631605              GhenxfiVXQaGbYq2_SXJhhkvTRN8M3vb
5    callback  globetrotter-394146   PdJEDeW57piXMu6nNsJjLZeFmNrP2jvG
6    callback  31831125              xupFcU6C8cl7wdviOnc1XX37Feg234vK

1 个答案:

答案 0 :(得分:0)

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

在这种情况下,如果我们从行(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更新,该更新将找到一个组,并为其分配一个新的(不同的)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值标记一组新的[未标记]行。

希望对您有帮助。