我有下表:
+---+---+
| A | B |
+---+---+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 2 | 3 |
| 4 | 4 |
+---+---+
我需要为每一行分配一个非唯一标识符(ID);此ID由每一行共享,在任一列中具有公共值。因此,第1行将具有与第2行相同的ID,但它也将具有与第3行相同的ID,第2行具有与第3行相同的ID。
我尝试将表连接到自身并使用RANK和DENSE_RANK函数来解决我的问题,但无济于事。我会在这里发布这些查询,但他们在帮助我实现目标方面是如此无关紧要,我可以想象他们最终会让人感到困惑。
请告诉我您的任何建议。
谢谢!
答案 0 :(得分:3)
您在原始问题描述中提到了传递性。这已经暗示了计算输入表中行的传递外壳的要求(如果它们共享A或B值,则两行相关)。因此,您需要一个递归查询来解决您的问题。
这是一个解决方案(SQL风格:PostgreSQL)。
DROP TABLE IF EXISTS pairs;
CREATE TABLE pairs (A int, B int);
INSERT INTO pairs VALUES
(1, 1),
(1, 2),
(2, 2),
(2, 3),
(4, 4);
WITH RECURSIVE hull(id, A, B) AS (
SELECT ROW_NUMBER() OVER () AS id, p.A, p.B
FROM pairs AS p
UNION
SELECT h.id, p.A, p.B
FROM hull AS h, pairs AS p
WHERE h.A IN (p.A, p.B) h.B IN (p.A, p.B)
)
SELECT MIN(h.id) AS id, h.A, h.B
FROM hull AS h
GROUP BY h.A, h.B;
结果:
┌────┬───┬───┐
│ id │ a │ b │
├────┼───┼───┤
│ 1 │ 2 │ 2 │
│ 1 │ 1 │ 1 │
│ 5 │ 4 │ 4 │
│ 1 │ 1 │ 2 │
│ 1 │ 2 │ 3 │
└────┴───┴───┘
编辑:这是一个应该在SQL Server中运行的变体(在递归CTE中不支持重复消除UNION
):
DECLARE @rows int = (SELECT COUNT(*) FROM pairs);
WITH hull(iter, id, A, B) AS (
SELECT 0 AS iter, ROW_NUMBER() OVER (ORDER BY p.A, p.B) AS id, p.A, p.B
FROM pairs AS p
UNION ALL
SELECT h.iter + 1, h.id, p.A, p.B
FROM hull AS h, pairs AS p
WHERE (h.B IN (p.A, p.B) OR h.A in (p.A, p.B))
AND h.iter < @rows
)
SELECT MIN(h.id) AS id, h.A, h.B
FROM hull AS h
GROUP BY h.A, h.B;
干杯,
-Torsten
答案 1 :(得分:1)
您可以使用lag()
window function确定两列的更改时间。到目前为止,对更改的运行总和会给出一个组号:
select A
, B
, sum(group_switch) over (order by A, B) as grp -- Running sum
from (
select case
when lag(A) over (order by A, B) = A or
lag(B) over (order by A, B) = B then 0 -- Same group
else 1 -- New group
end as group_switch
, *
from Table1
) sub
order by
A
, B
答案 2 :(得分:0)
你所说的是你有一堆集合,并且你想要给予彼此相交的所有集合,甚至是传递上相同的名称。
那么,对于所有(1,2),(1,3),(4,1),给出相同的名称,对吗?
所以你应该做的是跟踪每个组的超级集。
您可以将值本身用作id。
按行 第一行ID是: id 1
第二行ID是: id 1_2
因为已经存在1行,所以这些行会将当前行的值添加到其ID中,然后得到:
id 1_2 id 1_2
第3行
id 2
因为已经存在2行,所以这些行会将当前行的值添加到自身。因为他们已经拥有它,所以没有任何反应:
结果
id 1_2 id 1_2 id 1_2
然后 id 1_2 id 1_2 id 1_2 id 2_3
变为: 然后 id 1_2_3 id 1_2_3 id 1_2_3 id 1_2_3
最后
然后 id 1_2_3 id 1_2_3 id 1_2_3 id 1_2_4
问题是,每次插入内容时,都必须重新计算所有当前成员的ID。
如果这不是一个选项,或者您不希望ID很漂亮,请不要更改ID。
给初始行一个随机和大的哈希值,然后找出你刚插入的行之前是否有任何现有行共享任何值。如果是,请为新行指定相同的哈希值。如果不是,则生成新哈希。
也许如果您要进行密集搜索,第一个选项会更好,但如果您要进行密集编写,第二个选项会更好。
希望它有所帮助。 :)