我见过类似但不完全相同的请求。
如果我有下表
Parent Child
1 2
1 3
4 3
5 1
6 1
5 7
8 9
我选择了“1”我会期待所有记录,其中一个是父母或孩子,但也是所有相关的父母和孩子,例如行“5,7”,因为5是“1”的父母
所以1的结果集是
Parent Child
1 2
1 3
4 3
5 1
6 1
5 7
因此 NOT 包含行
Parent Child
8 9
这是我到目前为止的最接近的
;WITH LinksDown AS (
SELECT *
FROM RecursiveTable
WHERE Parent = 1
UNION ALL
SELECT rt.*
FROM RecursiveTable rt
JOIN LinksDown ld on ld.Child = rt.Parent
),
LinksUp AS (
SELECT *
FROM RecursiveTable
WHERE Child = 1
UNION ALL
SELECT rt.*
FROM RecursiveTable rt
JOIN LinksUp lu on lu.Child = rt.Parent
)
select distinct *
from LinksDown
Union All
select distinct * from LinksUp
但是这有以下输出,远不是什么需要
Parent Child
1 2
1 3
1 2
1 3
5 1
6 1
答案 0 :(得分:2)
我认为您仍然可以使用CTE执行此操作,作为存储过程的一部分。 (表现会很糟糕,但这应该有效。)
使用递归CTE的常规方法通常会生成3列:ParentID,ChildID,RecursionLevel。
我的建议是再返回一列......一个字符串,它是所有父ID的串联。 (可能有一些分隔符值,如垂直管道。)从那里,您应该能够选择IDString
列包含您的ID的每一行。 (在您的情况下,它将是" 1"。)这应该返回您的搜索ID出现在层次结构中某处的每个记录,而不仅仅是父或子。
编辑:以下是一个示例。我使用大括号{和}作为我的分隔符,我也意识到如果我添加一个" IsLeaf"那么代码会更干净。减少重复的指标,因为叶级记录将包含所有祖先的ID ......
DECLARE @MyTable TABLE(P int, C int) -- Parent & Child
INSERT @MyTable VALUES( 1, 2 );
INSERT @MyTable VALUES( 1, 3 );
INSERT @MyTable VALUES( 3, 4 );
INSERT @MyTable VALUES( 3, 5 );
INSERT @MyTable VALUES( 2, 6 );
INSERT @MyTable VALUES( 5, 7 );
INSERT @MyTable VALUES( 6, 8 );
INSERT @MyTable VALUES( 8, 9 );
-- In order to user a recursive CTE, you need to "know" which records are the 'root' records...
INSERT @MyTable VALUES ( null, 1 );
/*
9
/
8
/
6
/
2
/
1 4 Using this example, if the user searched for 1, everything would show up.
\ / Searching for 3 would return 1, 3, 4, 5, 7
3 Searching for 7 would return 1, 3, 5, 7
\
5
\
7
*/
WITH RecursiveCTE AS (
SELECT C as ID,
0 as Level,
CONVERT(varchar(max), '{' + CONVERT(char(1), C) + '}') as IDList,
CASE WHEN EXISTS (SELECT * FROM @MyTable B Where B.P = 1) THEN 0 ELSE 1 END as IsLeaf
FROM @MyTable A
Where A.P IS NULL
UNION ALL
SELECT child.C as ID,
Level + 1 as Level,
IDList + '{' + CONVERT(varchar(max), child.C) + '}' as IDList,
CASE WHEN EXISTS (SELECT * FROM @MyTable C Where C.P = child.C) THEN 0 ELSE 1 END as IsLeaf
FROM RecursiveCTE as parent
INNER JOIN @MyTable child ON child.P = parent.ID
)
SELECT IDList -- Every ID listed here is a row that you want.
FROM RecursiveCTE
WHERE IsLeaf = 1
AND IDList LIKE '%{3}%'
答案 1 :(得分:2)
这是两种方法。第一种使用效率非常低的CTE。问题是在递归期间,您无法检查结果集中的所有其他行。虽然您可以构建已贡献给给定行的行的列表,但您无法检查是否已通过其他路径到达该行。第二种方法使用循环一次一步地填充表关系。这是一种比CTE更好的方法。
留给读者的练习:这两种方法是否会在"树"中存在循环时终止,例如1> 2> 3> 1?
-- Sample data.
declare @RecursiveTable as Table ( Parent Int, Child Int );
insert into @RecursiveTable ( Parent, Child ) values
( 1, 2 ), ( 1, 3 ),
( 4, 3 ),
( 5, 1 ),
( 6, 1 ),
( 5, 7 ),
( 8, 9 );
select * from @RecursiveTable;
-- Walk the tree with a recursive CTE.
-- NB: This is woefully inefficient since we cannot promptly detect
-- rows that have already been processed.
declare @Start as Int = 1;
with Pairs as (
select Parent, Child, Cast( Parent as VarChar(10) ) + '/' + Cast( Child as VarChar(10) ) as Pair
from @RecursiveTable ),
Relations as (
select Parent, Child, Cast( '|' + Pair + '|' as VarChar(1024) ) as Path
from Pairs
where Parent = @Start or Child = @Start
union all
select P.Parent, P.Child, Cast( R.Path + P.Pair + '|' as VarChar(1024) )
from Relations as R inner join
Pairs as P on P.Child = R.Parent or P.Parent = R.Child or
P.Child = R.Child or P.Parent = R.Parent
where CharIndex( '|' + P.Pair + '|', R.Path ) = 0
)
-- To see how terrible this is, try: select * from Relations
select distinct Parent, Child
from Relations
order by Parent, Child;
-- Try again a loop to add relations to a working table.
declare @Relations as Table ( Parent Int, Child Int );
insert into @Relations
select Parent, Child
from @RecursiveTable
where Parent = @Start or Child = @Start;
while @@RowCount > 0
insert into @Relations
select RT.Parent, RT.Child
from @Relations as R inner join
@RecursiveTable as RT on RT.Child = R.Child or RT.Parent = R.Parent or
RT.Child = R.Parent or RT.Parent = R.Child
except
select Parent, Child
from @Relations;
select Parent, Child
from @Relations
order by Parent, Child;
答案 2 :(得分:1)
效率不高但它能胜任:
<android.support.design.widget.FloatingActionButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"
android:src="@drawable/ic_discuss"
android:layout_margin="@dimen/fab_margin"
android:clickable="true"/>
表格将是
select * from pc;
declare @t table (cid int);
declare @r int;
insert into @t (cid)values(1); -- this is the "parent"
set @r=@@rowcount;
while @r>0 begin
insert into @t
(cid) select pid from pc where (pid in (select cid from @t) or cid in (select cid from @t) ) and pid not in (select cid from @t)
union select cid from pc where (pid in (select cid from @t) or cid in (select cid from @t) ) and pid not in (select cid from @t);
set @r = @@ROWCOUNT;
end;
select * from pc where pid in (select cid from @t) or cid in (select cid from @t);
输出将是:
1 2
1 3
4 3
5 1
6 1
5 7
8 9
答案 3 :(得分:0)
///我尝试使用我的树形结构数据源:|
;WITH items AS (
SELECT Cg_Code, Cg_Name
, 0 AS Level
, CAST(Cg_Name AS VARCHAR(255)) AS Path
FROM GroupsCustomer WHERE Cg_Relation =0
UNION ALL
SELECT i.Cg_Code, i.Cg_Name
, Level + 1
, CAST(Path + '/' + CAST(i.Cg_Name AS VARCHAR(255)) AS VARCHAR(255)) AS Path
FROM GroupsCustomer i
INNER JOIN items itms ON itms.Cg_Code = i.Cg_Relation
)
SELECT * FROM items ORDER BY Path