【问题标题】:SQL Server: recursive self join of a table (no WITH clause)SQL Server:表的递归自连接(无 WITH 子句)
【发布时间】:2014-03-26 04:09:54
【问题描述】:

我有下表:

CREATE TABLE routes
(
    ID int identity not null primary key,
    from int,
    to int,
    length int not null
)

我需要从指定的ID1 到ID2 的所有路由。

我听说过WITH 子句,但我一点也不满意。它不允许轻松搜索从ID1 到ID2 的方式,因为它只返回一个包含FROM 和TO 值的表,并且很难搜索所有可能的方式。

我需要递归内连接之类的东西 - 例如:

SELECT * 
FROM routes r1
INNER JOIN routes r2 ON (r1.to = r2.from AND r2.to <> r1.from AND r1.from = ID1)

它让我寻找由 2 条路线组成的所有方式,从 ID1 开始,但不是那些去某个地方然后回到 ID1 的路线。现在我可以选择以 ID2 结尾的所有路由(可能为 NULL,但可能会出现某些东西)。如果有一条或多条路线在 ID2 结束,我想中断,如果没有,我想与路线 r3 内连接并重复过程,直到找到一条路线。

我可以在过程和 IF 子句中做到这一点,但我认为必须有更好的解决方案。

正如我所说,WITH 子句不能让我满意,因为它不能让我轻松找到所有路线,只有一条。

【问题讨论】:

  • 你需要一个递归语句,递归 CTE 就是你所需要的。
  • ...我们假设 SQL Server 有点风格?
  • SQL Server,我更正了描述。如我所见,递归 CTE 使用 WITH 子句并在单行中返回所有路由,因此无法轻松选择在指定 ID2 上完成的所有方式
  • 正如 Gordon 提到的,递归 CTE 应该是要走的路。最近写了一个HERE-post link,想参考一下入手。
  • 递归 CTE 可能很棘手,所以我承认您可能不会“轻易”找到它们,但它们可以处理分支,并且可能会更优雅地处理其他循环递归过程。我们可以假设沿路线的步数有特定限制吗? 5? 10? 100? 1000?

标签: sql sql-server recursion inner-join


【解决方案1】:
  1. 我改变了一些东西,使它更容易玩。例如,避免将 [from] 和 [to] 作为列名。
  2. 我对 ID1 和 ID2 进行了硬编码,而不是使用变量。
  3. 我不担心“长度”。
  4. 您会看到它找到迂回路线,但不会让它们重复任何步骤。
  5. 未优化 - 仅展示其工作原理。
  6. 我在固定代码格式时遇到了一些麻烦。我会发布并尝试编辑。
  7. 底部的小提琴链接。

创建表路由( ID int /identity/ not null 主键 ,开始 char(1)--int ,完成 char(1)--int --,[length] int 不为空 )

GO

INSERT INTO routes VALUES 
  (1,'a','b')
 ,(2,'a','c')
 ,(3,'a','d')
 ,(4,'b','c')
 ,(5,'b','d')
 ,(6,'c','d')
 ,(7,'d','c')

GO

WITH cte AS (
 --anchor
 SELECT id
       ,start
       ,finish
       ,',' + CAST(id AS VARCHAR(MAX)) + ',' route_ids
   FROM routes
  WHERE start = 'a'

  UNION ALL
 --recursive part    
 SELECT a.id
       ,a.start
       ,b.finish
       ,route_ids + CAST(b.id AS VARCHAR(MAX)) + ','
   FROM cte a
        INNER JOIN
        routes b ON a.finish = b.start 
  WHERE CHARINDEX(',' + CAST(b.id AS VARCHAR(MAX)) + ',',a.route_ids,1)  = 0
)
SELECT start,finish,route_ids 
 FROM cte
WHERE finish = 'c'
ORDER BY LEN(route_ids)

Fiddle

【讨论】:

  • 你的回答真的很棒,我已经得到了我需要的东西。下一个问题是:如何从 ,a,b,c,... 字符串(数字)中获取值到单独的表中?我需要像 (1,a), (2,b), (3,c) 等在一张桌子上。
  • 啊。是的,您还需要一个拆分功能。看看这里stackoverflow.com/questions/43249/…。
猜你喜欢
  • 1970-01-01
  • 2013-12-06
  • 2017-08-14
  • 2017-05-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多