假设我有一个包含父子关系的表。
parent child 1 4 1 5 2 6 3 7 4 8 6 9 7 10 8 11
现在我有一个返回人员列表的查询(例如1和2),我想找到他们所有的孩子,孙子等等(在这种情况下:4,5,6,8,9,11) 。
我知道我可以使用公共表表达式来递归搜索,但我想知道是否可以创建一个SQL语句来一次查找所有后代而不必迭代输入集。
编辑:抱歉不够清楚。我正在寻找类似的东西:
SELECT {Hierarchical relation} from table where parent in (1,2)
这将导致单个输出列的行为4,5,6,8,9,11。
我不再对输出中的关系感兴趣,只是对多个家庭的完整家庭成员感兴趣。
答案 0 :(得分:17)
这是
---- PlainTable ----
parent idElement (child)
Null 1
1 4
1 5
2 6
3 7
4 8
6 9
7 10
8 11
WITH tableR (parent, idElement)
AS
(
-- Anchor member definition
SELECT e.parent, e.idElement
FROM PlainTable AS e
WHERE parent in (1,2)
UNION ALL
-- Recursive member definition
SELECT e.parent, e.idElement
FROM PlainTable AS e
INNER JOIN tableR AS d
ON e.parent = d.idElement
)
-- Statement that executes the CTE
SELECT idElement
FROM tableR --inner join to plain table by id if needed
答案 1 :(得分:0)
SQL Server 2008内置了一些功能来促进分层数据:http://msdn.microsoft.com/en-us/magazine/cc794278.aspx
我知道我可以使用公用表表达式来递归搜索,但是我 想知道我是否可以创建一个SQL语句来查找所有后代 一次无需迭代输入集。
我不确定你的意思。大多数(可能全部?)CTE可以通过使用子查询来完成,但使用子查询不会更快。当你说你不想“迭代”输入集时,听起来你正在谈论游标的使用,当然你可以把它作为基于集合的操作(使用CTE或子查询)来做但是没有围绕递归的方式。
编辑:对不起,我不是直接思考...当然你不能用正常的子查询进行递归但是这一点仍然存在,即使你可能它也不会更快。如果你想在没有CTE的情况下看到进行递归的策略,那么尝试搜索类似'recursion sql 2000'的东西,因为CTE不在那时。以下是一些示例:http://www.mssqltips.com/sqlservertip/938/recursive-queries-with-sql-server-2000/。当然,你问题的答案仍然是一样的。
答案 2 :(得分:0)
使用 CTE
使用公用表表达式的递归查询
http://msdn.microsoft.com/en-us/library/ms186243.aspx
和
http://www.sqlservercentral.com/articles/T-SQL/65540/
可以帮到你。
答案 3 :(得分:0)
在等待更新的帖子时:
SELECT DISTINCT
p.parent AS parent
, c.child AS child
, IFNULL(g.child, 'NONE') AS grandchild_of_parent
FROM parent_child as p
LEFT JOIN parent_child AS c ON p.parent = c.parent
LEFT JOIN parent_child AS g ON c.child = g.parent;
结果如下:
parent child grandchild_of_parent
1 4 8
1 5 NONE
2 6 9
3 7 10
4 8 11
6 9 NONE
7 10 NONE
8 11 NONE
这种简单但可能更难维护的代码类型,但由于我不熟悉SQL Server 2008的内置功能来处理这种类型的请求,所以我只会抛出很长时间镜头...
因此,当您学习common table expressions
和/或pivots
时,您可以自己查看结果...这将得到您的结果,但仅限于1和2的曾孙。 / p>
-- A. Parents 1 and 2
SELECT DISTINCT p.parent FROM parent_child AS p
WHERE p.parent IN (1,2)
UNION
-- B : Children of A
SELECT DISTINCT p.child FROM parent_child AS p
WHERE p.parent IN (1,2)
UNION
-- C : Children of B, Grandchildren of A
SELECT DISTINCT p.child FROM parent_child AS p
WHERE p.parent IN (
SELECT DISTINCT p.child FROM parent_child AS p
WHERE p.parent IN (1,2)
)
UNION
-- D : Children of C, Great-Grandchildren of A
SELECT DISTINCT p.child FROM parent_child AS p
WHERE p.parent IN (
SELECT DISTINCT p.child FROM parent_child AS p
WHERE p.parent IN (
SELECT DISTINCT p.child FROM parent_child AS p
WHERE p.parent IN (1,2)
)
)
同样,我强烈建议你研究其他人发布的内容......并查看他们提供的链接。我提供给你的不优雅的查询不会持久 - >一旦你有了曾孙子,它绝对会FAIL
。
答案 4 :(得分:0)
通常我使用Nested Set Model来表示你可以让SQL为你做所有的工作,实际上你有SQL输出XML可以直接附加到.net treeview。希望这有帮助
答案 5 :(得分:0)
好吧,danihp的解决方案确实让我走上正轨。这是我提出的解决方案:
DECLARE @Input TABLE (
id int
)
INSERT INTO @Input VALUES (1),(2)
;WITH Relations (parent, child)
AS
(
SELECT e.parent, e.child
FROM RelationTable AS e
WHERE parent in (SELECT * FROM @Input)
UNION ALL
SELECT e.parent, e.child
FROM RelationTable AS e
INNER JOIN Relations AS d
ON e.parent = d.child
)
SELECT child
FROM Relations
它会生成一个子ID列表(不包括我之前在问题中所说的2个父ID): 4,5,6,8,9,11
答案 6 :(得分:0)
---- PlainTable ----
parent idElement (child_id)
Null 1
1 4
1 5
2 6
3 7
4 8
6 9
7 10
8 11
**Table value function to get Child ids at 4(any) Level of parent in the same table:-**
FUNCTION fc_get_Child_IDs(Parent)
DECLARE @tbl TABLE (ID int)
DECLARE @level int=4
DECLARE @i int=1
insert into @tbl values (Parent)
while @i < @level
BEGIN
INSERT into @tbl
select child_id from PlainTable where Parent in (select ID from @tbl) and child_id not in (select ID from @tbl)
set @i = @i + 1
END