我有一个SQL Server 2005表,如下所示:
parent child
1 a
2 a
2 b
3 b
3 c
4 c
5 d
6 d
7 d
8 e
9 e
9 f
10 f
每个父母可以有一个或多个孩子,每个孩子也可以有一个或多个父母。 我怎样才能找到(或分组)所有相关的父母?
在上述情况下,我想分组:
parent 1, 2, 3, 4 into group 1
parent 5, 6, 7 into group 2
parent 8, 9, 10 into group 3
查询的结果如下所示:(无论哪个父级用作组,只要它来自组中的父级之一,最小ID或最大ID就可以了)
parent child parent_group
1 a 1
2 a 1
2 b 1
3 b 1
3 c 1
4 c 1
5 d 5
6 d 5
7 d 5
8 e 8
9 e 8
9 f 8
10 f 8
这类似于那些标准boss - 下属递归SQL问题,但下属可能有超过1个boss。
是否可以使用SQL生成上述结果?如果是这样的话?
感谢任何帮助。
答案 0 :(得分:1)
在单个查询中无法执行此操作。我发现a blog post(带some ruby code)描述了如何计算SQL中的连通组件(MySQL风格)。
基于这篇文章,我编写了以下SQL(SQL Server风格):
-- Step 1: Create temporary tables
CREATE TABLE #items (
id int PRIMARY KEY,
component_id int
);
CREATE TABLE #links (
first int,
second int,
PRIMARY KEY (first, second)
);
CREATE TABLE #components_to_merge (
component1 int,
component2 int
PRIMARY KEY (component1, component2)
);
-- Step 2: Populate tables
INSERT INTO #items (id, component_id)
SELECT DISTINCT parent, parent
FROM children;
INSERT INTO #links (first, second)
SELECT DISTINCT c1.parent, c2.parent
FROM children c1
INNER JOIN children c2 ON c1.child = c2.child
WHERE c1.parent <> c2.parent;
-- Step 3: Merge components
WHILE 1 = 1 BEGIN
-- Step 3.1: Update #components_to_merge
TRUNCATE TABLE #components_to_merge;
INSERT INTO #components_to_merge (component1, component2)
SELECT DISTINCT t1.component_id, t2.component_id
FROM #links l
INNER JOIN #items t1 ON t1.id = l.first
INNER JOIN #items t2 ON t2.id = l.second
WHERE t1.component_id <> t2.component_id;
INSERT INTO #components_to_merge (component1, component2)
SELECT component2, component1
FROM #components_to_merge m1
WHERE component2 NOT IN (
SELECT m2.component2
FROM #components_to_merge m2
WHERE m2.component1 = m1.component1
);
IF (SELECT COUNT(*) FROM #components_to_merge) = 0
BREAK;
-- Step 3.2: Update #items
UPDATE i
SET component_id = target
FROM #items i
INNER JOIN (
SELECT
component1 AS source,
MIN(component2) AS target
FROM #components_to_merge
GROUP BY component1
) new_components
ON source = component_id
WHERE target < component_id;
END;
-- Step 4: Generate result
SELECT parent, child, component_id
FROM children
INNER JOIN #items ON id = parent;
您可以将其包装在存储过程中:
CREATE PROCEDURE CalculateComponents AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION;
-- SQL code from above
ROLLBACK TRANSACTION;
END;
然后用
调用它EXEC CalculateComponents;
输出:
parent child component_id
1 a 1
2 a 1
2 b 1
3 b 1
3 c 1
4 c 1
5 d 5
6 d 5
7 d 5
8 e 8
9 e 8
9 f 8
10 f 8