我有桌子:
ID Person_ID Person_Relative_ID
1 10 20
2 20 30
3 13 15
4 30 40
5 55 56
6 40 50
在这里,我们可以看到人与人。 person_relative_id
链条大概是10 - 20 - 30 - 40 - 50
现在,如果用户搜索Person_Relative_ID
= 20的person_id
,那么结果就像:[所有关系]
Person_Relative_ID
10
30
40
50
或者用户想要Person_Relative_ID
搜索person_id
= 40。然后结果像
Person_Relative_ID
10
20
30
50
或者用户想要Person_Relative_ID
搜索person_id
= 50。然后结果像
Person_Relative_ID
10
20
30
40
任何建议都非常感谢。
答案 0 :(得分:1)
嗯,我不确定这是性能最有效的解决方案,而且我喜欢处理单个递归CTE而不是两个,但这至少有效。
用你的真实表替换对我用来测试它的临时表的引用。但它的作用是,它使用两个递归CTE来查找上面的所有引用(CTEUp)和下面(CTEDown)您的ID,然后按顺序显示它们,除了您搜索到的ID。
注意:这适用于SQL Server,而非Oracle。
-- Creating dummy variables for testing
DECLARE @PERSONS TABLE (ID INT IDENTITY(1,1), Person_ID INT, Person_Relative_ID INT)
INSERT INTO @PERSONS VALUES (10,20), (20,30), (13,15), (30,40), (55,56), (40,50)
-- Variable for searched ID, the actual script begins here
DECLARE @SEARCHED_ID INT
SET @SEARCHED_ID = 20
;WITH CTEUp AS
-- Fetching all relations above the ID
(SELECT Person_ID
FROM @PERSONS
WHERE Person_ID = @SEARCHED_ID
UNION ALL
SELECT Person_Relative_ID
FROM @PERSONS P
JOIN CTEUp C ON C.Person_ID = P.Person_ID
AND P.Person_Relative_ID > C.Person_ID)
, CTEDown AS
-- Fetching all relations below the ID
(SELECT Person_ID
FROM @PERSONS
WHERE Person_Relative_ID = @SEARCHED_ID
UNION ALL
SELECT P.Person_ID
FROM @PERSONS P
JOIN CTEDown C ON C.Person_ID = P.Person_Relative_ID
AND P.Person_ID < C.Person_ID)
-- Showing results
SELECT Person_ID
FROM
(SELECT *
FROM CTEDown
UNION ALL
SELECT *
FROM CTEUp) SRC
WHERE Person_ID <> @SEARCHED_ID --... minus the ID, as per your example
ORDER BY Person_ID ASC
答案 1 :(得分:1)
刚刚尝试了Oracle,可能会更好但仍然有效
with tab(ID, Person_ID, Person_Relative_ID) as (
SELECT 1, 10, 20 from dual union all
SELECT 2, 20, 30 from dual union all
SELECT 3, 13, 15 from dual union all
SELECT 4, 30, 40 from dual union all
SELECT 5, 55, 56 from dual union all
SELECT 6, 40, 50 from dual),
---------
--End of data preparation
---------
filter_tab as (
select 40 as id from dual), --> Put the search id here
final_tab(person_id) as (
select person_id
from tab
start with person_relative_id = (select id from filter_tab)
connect by prior person_id = person_relative_id
union
select person_relative_id
from tab
start with person_id = (select id from filter_tab)
connect by prior person_relative_id = person_id)
select *
from final_tab
where not exists (select 'x'
from filter_tab
where id = person_id )
order by 1;
输出:
PERSON_ID
---------
10
20
30
50
我刚刚从起点遍历到两端,结果联合并排除了搜索ID。
答案 2 :(得分:0)
在SQL Server 2012及更高版本中,您可以使用LAG和LEAD功能。 这是一个示例:
SELECT TOP 1000 [n], LAG([n]) OVER(ORDER BY [n] ), LEAD([n]) OVER (ORDER BY [n])
FROM [dbo].[Nums]
它会产生结果:
n LAG LEAD
1 NULL 2
2 1 3
3 2 4
4 3 5
5 4 6
答案 3 :(得分:0)
如果您使用的是SQL2005及更高版本,SQL Recursive CTE结构化SQL查询可用于查询分层数据模型(如您的情况)
以下查询还使用multiple CTE queries来防止使用不必要的临时表或表变量
declare @id smallint = 50
;with cte as (
select Person_ID, Person_Relative_ID
from PersonRelative
where Person_ID = @id OR Person_Relative_ID = @id
union all
select P.Person_ID, P.Person_Relative_ID
from PersonRelative P
inner join CTE on CTE.Person_ID = P.Person_Relative_ID
), cte2 as (
select Person_ID from cte
union
select Person_Relative_ID from cte
), cte3 as (
select Person_ID, Person_Relative_ID
from PersonRelative
where Person_ID = @id OR Person_Relative_ID = @id
union all
select P.Person_ID, P.Person_Relative_ID
from PersonRelative P
inner join CTE3 on CTE3.Person_Relative_ID = P.Person_ID
), cte4 as (
select Person_ID from cte3
union
select Person_Relative_ID from cte3
)
select * from cte4 where Person_ID <> @id
union
select * from cte2 where Person_ID <> @id