我有一张这样的桌子:
from | to
-----+-----
23 | 24
24 | 25
25 | 27
27 | 30
45 | 46
46 | 47
50 | 52
53 | 60
我需要一个SQL Server查询来检测链的并返回每个链中的min(从)和max(至)(还有一条记录的链):
from | to
-----+-----
23 | 30
45 | 47
50 | 52
53 | 60
[这是使用递归CTE的方法。
CREATE TABLE #chainLinks(linkFrom INTEGER, linkTo INTEGER);
INSERT INTO #chainLinks VALUES (23,24);
INSERT INTO #chainLinks VALUES (24,25);
INSERT INTO #chainLinks VALUES (25,27);
INSERT INTO #chainLinks VALUES (27,30);
INSERT INTO #chainLinks VALUES (45,46);
INSERT INTO #chainLinks VALUES (46,47);
INSERT INTO #chainLinks VALUES (50,52);
INSERT INTO #chainLinks VALUES (53,60);
WITH reccte AS
(
/*Recursive Seed*/
SELECT linkFrom AS chainStart,
linkFrom,
linkTo,
0 as links
FROM #chainLinks as chainLinks
WHERE linkFrom NOT IN (SELECT DISTINCT linkTo FROM #chainLinks)
UNION ALL
/*Recursive Term*/
SELECT
reccte.chainStart,
chainLinks.linkFrom,
chainLinks.linkTo,
links + 1
FROM reccte
INNER JOIN #chainLinks as chainLinks ON reccte.linkTo = chainLinks.linkFrom
)
SELECT chainStart, linkTo AS chainEnd
FROM
(
SELECT chainStart, linkFrom, linkTo, links, ROW_NUMBER() OVER (PARTITION BY chainStart ORDER BY links DESC) AS rn
FROM reccte
)subrn
WHERE rn = 1;
递归CTE分为两个部分
UNION
上方的部分,我们在其中确定表中的哪些记录开始递归。在这里,我们要的是linkFrom
也不是linkTo
UNION
下方的部分,我们在其中将名为reccte
的cte连接回原始表。 CTE的这一部分反复迭代,直到连接失败。 在这里,我们还跟踪links
,它只是我们到达该输出记录所经过的迭代次数的计数器。对于每个起点links
,我们保留最高的chainStart
数。
这里是工作示例:https://rextester.com/JWUW57837
如果链中有链,则将变得有些棘手。
create table yourtable ( [From] int not null, [To] int not null, PRIMARY KEY ([From],[To]) ) GO
✓
insert into yourtable ([From],[To]) values (2,3),(3,5),(5,4) ,(14,12),(12,15),(15,11),(11,10) ,(12,9) ,(21,23) GO
9行受影响
;WITH RCTE_CHAINS AS ( -- seeding with the start of chains SELECT [From] AS MinFrom, [From], [To], 0 AS Lvl , CAST(IIF(EXISTS( SELECT 1 FROM YourTable n WHERE n.[From] = t.[To] ),1,0) AS BIT) AS hasNext FROM YourTable t WHERE NOT EXISTS ( SELECT 1 FROM YourTable t2 WHERE t2.[To] = t.[From] ) UNION ALL -- looping through the childs SELECT c.MinFrom, t.[From], t.[To], c.Lvl+1 , CAST(IIF(EXISTS( SELECT 1 FROM YourTable n WHERE n.[From] = t.[To] ),1,0) AS BIT) AS hasNext FROM RCTE_CHAINS c JOIN YourTable t ON t.[From] = c.[To] ) SELECT MinFrom AS [From], [To] FROM RCTE_CHAINS WHERE hasNext = 0 GO
来自|至---: -:21 | 2314 | 914 | 102 | 4
db <>小提琴here