分组按A或B列

时间:2018-04-18 17:19:46

标签: sql sql-server tsql

我有下表:

+---+---+
| 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函数来解决我的问题,但无济于事。我会在这里发布这些查询,但他们在帮助我实现目标方面是如此无关紧要,我可以想象他们最终会让人感到困惑。

请告诉我您的任何建议。

谢谢!

3 个答案:

答案 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

Example at SQL Fiddle.

答案 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。

给初始行一个随机和大的哈希值,然后找出你刚插入的行之前是否有任何现有行共享任何值。如果是,请为新行指定相同的哈希值。如果不是,则生成新哈希。

也许如果您要进行密集搜索,第一个选项会更好,但如果您要进行密集编写,第二个选项会更好。

希望它有所帮助。 :)