【问题标题】:How to rewrite this query (PostgreSQL) in SQL Server?如何在 SQL Server 中重写此查询(PostgreSQL)?
【发布时间】:2013-11-14 23:16:04
【问题描述】:

几天前,我问了一个关于 1,2 和 3. 度连接的问题。 Question Link 和 @Snoopy 提供了一个文章链接,可以解决我的所有问题。 Article Link

我仔细检查了这篇文章,但我无法在 SQL Server 中使用 With Recursive query。

PostgreSQL 查询:

SELECT a AS you,
   b AS mightknow,
   shared_connection,
   CASE
     WHEN (n1.feat1 = n2.feat1 AND n1.feat1 = n3.feat1) THEN 'feat1 in common'
     WHEN (n1.feat2 = n2.feat2 AND n1.feat2 = n3.feat2) THEN 'feat2 in common'
     ELSE 'nothing in common'
   END AS reason
 FROM (
 WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
 ( SELECT a, b, 1 AS distance,
     a || '.' || b || '.' AS path_string,
     b AS direct_connection
FROM edges2
 WHERE a = 1 -- set the starting node

 UNION ALL

 SELECT tc.a, e.b, tc.distance + 1,
     tc.path_string || e.b || '.' AS path_string,
     tc.direct_connection
FROM edges2 AS e
JOIN transitive_closure AS tc ON e.a = tc.b
 WHERE tc.path_string NOT LIKE '%' || e.b || '.%'
 AND tc.distance < 2
 )
 SELECT a,
   b,
   direct_connection AS shared_connection
 FROM transitive_closure
 WHERE distance = 2
 ) AS youmightknow
 LEFT JOIN nodes AS n1 ON youmightknow.a = n1.id
 LEFT JOIN nodes AS n2 ON youmightknow.b = n2.id
 LEFT JOIN nodes AS n3 ON youmightknow.shared_connection = n3.id
 WHERE (n1.feat1 = n2.feat1 AND n1.feat1 = n3.feat1)
 OR (n1.feat2 = n2.feat2 AND n1.feat2 = n3.feat2);

或者只是

WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
( SELECT a, b, 1 AS distance,
     a || '.' || b || '.' AS path_string
FROM edges
WHERE a = 1 -- source

UNION ALL

SELECT tc.a, e.b, tc.distance + 1,
     tc.path_string || e.b || '.' AS path_string
FROM edges AS e
JOIN transitive_closure AS tc ON e.a = tc.b
WHERE tc.path_string NOT LIKE '%' || e.b || '.%'
)
SELECT * FROM transitive_closure
WHERE b=6 -- destination
ORDER BY a, b, distance;

正如我所说,我不知道如何使用 CTE 使用 SQL Server 编写递归查询。进行了搜索并检查了this page,但仍然没有运气。我无法运行查询。

【问题讨论】:

    标签: sql sql-server postgresql common-table-expression recursive-query


    【解决方案1】:

    如果有人感兴趣,这里是答案;

    我设法通过以下方式将相关查询转换为 SQL;

    1. 将整数值转换为 varchar(MAX)。如果您没有将 varchar 的长度指定为 MAX,您将得到“锚点和列中的递归部分之间的类型不匹配...”

    2. 我替换了 ||到 +

    3. 我添加了;到查询的开头

    4. 最后按照@a_horse_with_no_name 的建议,我从查询中删除了 RECURSIVE。

    结果;

    ;WITH transitive_closure(a, b, distance, path_string) AS
    ( SELECT a, b, 1 AS distance,
     CAST(a as varchar(MAX)) + '.' + CAST(b as varchar(MAX)) + '.' AS path_string
    FROM edges
    WHERE a = 1 -- source
    
    UNION ALL
    
    SELECT tc.a, e.b, tc.distance + 1, 
    CAST(tc.path_string as varchar(MAX)) + CAST(e.b as varchar(MAX)) + '.' AS path_string
    FROM edges AS e
    JOIN transitive_closure AS tc ON e.a = tc.b
    WHERE tc.path_string NOT LIKE '%' + CAST(e.b as varchar(MAX)) + '.%'
    )
    SELECT * FROM transitive_closure
    WHERE b=6 -- destination
    ORDER BY a, b, distance;
    

    【讨论】:

      【解决方案2】:

      递归 CTE 在 SQL Server 上应该是相同的(至少在最近的版本中,如果我没记错的话,这是在 SQL Server 2005 中引入的),只需省略 recursive 关键字。

      请注意,SQL Server 不符合 SQL 标准,因此您需要将 || 连接替换为 +

      【讨论】:

      • 我删除了递归并且它可以工作,但我无法运行此查询。 SELECT edges.a as a, edges.b as b, 1 AS distance, a + '.' + b + '.' as path FROM edges 错误:转换 varchar 值 '.' 时转换失败到数据类型 int 我尝试使用 CAST 但没有成功。
      • @Burak:显然 ab 不是 varchar 列。您将需要强制转换它们才能连接它们。试试cast(edges.a as varchar) + '.' + cast(edges.b as varchar)
      • 我设法运行了这个查询:SELECT edges.a as a, edges.b as b, 1 AS distance, CAST(a AS VARCHAR(10)) + '.' + CAST(b AS VARCHAR(10)) + '.' as path FROM edges
      猜你喜欢
      • 2013-02-01
      • 2016-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 2015-08-14
      • 2013-01-17
      相关资源
      最近更新 更多