SQL Server查找两列之间的链

问题描述 投票:0回答:2

我有一张这样的桌子:

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
sql-server
2个回答
4
投票

[这是使用递归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分为两个部分

  1. 递归种子-这是UNION上方的部分,我们在其中确定表中的哪些记录开始递归。在这里,我们要的是linkFrom也不是linkTo
  2. 隐性术语-这是UNION下方的部分,我们在其中将名为reccte的cte连接回原始表。 CTE的这一部分反复迭代,直到连接失败。

在这里,我们还跟踪links,它只是我们到达该输出记录所经过的迭代次数的计数器。对于每个起点links,我们保留最高的chainStart数。

这里是工作示例:https://rextester.com/JWUW57837


0
投票

如果链中有链,则将变得有些棘手。

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

© www.soinside.com 2019 - 2024. All rights reserved.