找到重定向链的开头和结尾

时间:2014-01-14 15:54:36

标签: sql-server sql-server-2012

我在SQL服务器表中有一个URL重定向表,每个重定向都有一个ID,一个FromURL和一个ToURL字段。

我被要求找到表格中有重定向链的地方,以便我们可以用一次重定向替换它们,这样用户只能重定向一次而不是多次。

该表的一个例子如下:

Sample Table

正如您所看到的,如果用户访问网址A,他们将被重定向到B,然后从B到C,然后从C到D,我们希望将其替换为从A到D的单个重定向以加快速度页面加载。

我想我可以在没有带有递归CTE的游标的情况下做到这一点,但我完全坚持了这一点,我设法做到的最好的是找到每个链的起点如下:

SELECT  r.ID ,
        r.FromURL ,
        r.ToURL
FROM    dbo.redirect r
WHERE   fromURL NOT IN ( SELECT ToURL
                         FROM   dbo.redirect r2 )

通过选择FromURL未被任何其他重定向重定向的任何记录,这给了我链的起点(或根本不在链中的链)。当我尝试通过一些递归的CTE示例时,我最终得到的只是垃圾数据或达到递归限制。

理想情况下,我想要解决的是与以下类似的数据:

Ideal result

正如您所看到的,重定向链已被替换为单个链,因此层次结构中的每个级别现在都直接进入链的末尾。

我只是一位同意为我们的网络团队做点什么的DBA,我现在已经完全发现了T-SQL的能力,所以如果有人能帮助我,那将是非常感激的。

1 个答案:

答案 0 :(得分:1)

可以找到一般解决方案,搜索:“Directed Acyclic Graph”,“Traversal”,“SQL”。 hansolav.net/sql/graphs.html#topologicalsorting有一些很好的信息。

如果您需要快速回答,这是一种快速而肮脏的方法。它效率不高,需要非循环输入,但对于不熟悉sql的人来说,它是可读的。

SELECT id, FromUrl, ToUrl
INTO #temp
FROM dbo.redirect

WHILE @@ROWCOUNT > 0
BEGIN
  UPDATE cur
  SET ToUrl = nxt.ToURL
  FROM #temp cur
  INNER JOIN #temp nxt ON (cur.ToURL = nxt.FromURL)
END

SELECT * FROM #temp

或者,使用递归CTE:

;WITH cte AS (
  SELECT 1 as redirect_count, id, FromURL, ToUrl
  FROM dbo.redirect
  UNION ALL
  SELECT redirect_count + 1, cur.id, cur.FromURL, nxt.ToURL
  FROM cte cur
  INNER JOIN @t nxt ON (cur.ToURL = nxt.FromURL)
)
SELECT
  t1.id, t2.FromUrl, t2.ToUrl
FROM dbo.redirect t1
CROSS APPLY (
  SELECT TOP 1 FromUrl, ToUrl
  FROM cte
  WHERE id = t1.id
  ORDER BY redirect_count DESC
) t2