【问题标题】:Oracle SYS_CONNECT_BY_PATH equivalent query into SQL ServerOracle SYS_CONNECT_BY_PATH 等效查询到 SQL Server
【发布时间】:2017-10-07 21:51:52
【问题描述】:

我正在尝试将涉及 Oracle SYS_CONNECT_BY_PATH 语法的复杂查询转换为 SQL Server:

    SELECT 
           DISTINCT TO_CHAR(CONCAT(@ROOT, SYS_CONNECT_BY_PATH(CONCAT('C_',X), '.'))) AS X_ALIAS
                , TO_CHAR(CONCAT(@ROOT, PRIOR SYS_CONNECT_BY_PATH(CONCAT('C_',X), '.'))) AS X_ALIAS_FATHER
                , TO_CHAR(X) AS X_ALIAS_LEAF
                , LEVEL AS LVL
      FROM MY_TABLE
 LEFT JOIN MY_TABLE_BIS MY_TABLE_BIS_ALIAS ON MY_TABLE_BIS_ALIAS.MY_ID = COL_X
 LEFT JOIN OTHER_TABLE 
        ON OTHER_TABLE.MY_ID = COL_X
CONNECT BY (PRIOR ID_SON = ID_FATHER)
       AND LEVEL <= MAXDEPTH
START WITH ID_FATHER 
        IN (SELECT AN_ID AS ID_FATHER FROM BIG_TABLE)

这是我使用this website获得的结果

WITH n(LEVEL, X_ALIAS, X_ALIAS_FATHER, X_ALIAS_LEAF) AS
      ( SELECT 1, CONCAT('C_',X), CONCAT('C_',X), CAST(X AS VARCHAR(30))
          FROM MY_TABLE
     LEFT JOIN MY_TABLE_BIS MY_TABLE_BIS_ALIAS 
            ON MY_TABLE_BIS_ALIAS.MY_ID = COL_X
     LEFT JOIN OTHER_TABLE 
            ON OTHER_TABLE.MY_ID = COL_X
         WHERE ID_FATHER IN (SELECT AN_ID AS ID_FATHER 
          FROM listAllCfaCfq)
     UNION ALL
        SELECT n.level + 1, n.X_ALIAS + '.' + nplus1.X_ALIAS, n.X_ALIAS_FATHER + '.' + nplus1.X_ALIAS_FATHER, CAST(X AS VARCHAR(30)
          FROM MY_TABLE
     LEFT JOIN MY_TABLE_BIS MY_TABLE_BIS_ALIAS 
            ON MY_TABLE_BIS_ALIAS.MY_ID = COL_X
     LEFT JOIN OTHER_TABLE 
            ON OTHER_TABLE.MY_ID = COL_X AS nplus1, n
         WHERE n.ID_SON = nplus1.ID_FATHER)
        SELECT DISTINCT LEVEL, X_ALIAS, X_ALIAS_FATHER, X_ALIAS_LEAF
         WHERE LEVEL <= @MAXDEPTH;

我更改了表格的名称,这样做可能会出错,请不要犹豫,在 cmets 中告诉我

【问题讨论】:

  • listAllCfaCfq 未被第一个查询引用。请为表格发布DDL
  • 能否提供表格数据
  • 如果您在 SQL Server 中使用 hierachyid(我无法确定,因为您还没有发布表结构),那么您可以使用 CAST(hierarchyid as nvarchar(100)) 来显示这样的路径: /2/1/2/1/ 每行
  • 不知道为什么这么多人赞成这个。它应该在提供 DDL 之前关闭。
  • 您已经回答了自己的问题,为什么不将其作为答案。有人纠正你的错误的机会很小。

标签: sql-server tsql hierarchical-data recursive-query


【解决方案1】:

都可以用几个FUNCTIONs来解决,用一些递归就很简单,(注意T-SQL的最大递归级别是32)

假设我们有下表:(对于一家非常小的公司)

TableName: Employees
id.....name..............manager_id
1      Big Boss          NULL
2      Sales Manager     1
3      Support Manager   1
4      R&D Manager       1               
5      Sales man         2
6      Support man       3
7      R&D Team leader   4
8      QA Team leader    4
9      C Developer       7
10     QA man            8
11     Java Developer    7      

我们只需要一个函数来检查 2 个 id 之间是否存在链接,以及另一个函数来给出从一个到另一个的路径。

第一个函数使用递归非常简单:

Create Function dbo.Do_WE_Have_path(@id int, @boss_id int, @max_level int) returns int
Begin
  declare @res int, @man int
  set @res = 0
  if @id = @boss_id 
    set @res = 1
  else if @max_level > 0 
  Begin
    Select @man=manager_id from Employees where id=@id
    set @res = Do_WE_Have_path(@man, @boss_id, @max_level-1) --recursion
  End
  return res 
End

使用上面的函数,我们可以选择所有连接短或等于指定级别的实体,所以现在我们可以编写一个方法,如果存在则构建路径,注意不存在的路径应该被过滤使用上述方法

Create Function dbo.Make_The_path(@id int, @boss_id int, @max_level int) returns varchar(max)
Begin
  declare @res varchar(max), @man int
  select @res = name from Employees where id=@id
  if max_level > 0 AND @id <> @boss_id
  Begin 
    select @man = manager_id from Employees where id = @id
    set @res = dbo.Make_The_path(@man, @boss_id, max_level-1) + '/' + @res
  End
  return @res
End

现在我们可以使用这两个函数来获取从老板到工人的路径:

Select dbo.Make_The_path(id, 1, 3) Where Do_WE_Have_path(id, 1, 3)=1    

两个函数都可以合并为一个,也许你需要为每个结构重新编写它,但重要的是它是可能的。

【讨论】:

    【解决方案2】:

    您可能希望对层次结构部分使用递归 CTE,然后使用 FOR XML 进行路径构建。 FOR XML 旨在将您的结果转换为 XML,但您可以使用它将结果转换为各种有趣的文本格式。

    FOR XML PATH clause in SQL Server

    FOR XML (SQL Server) Microsoft Reference

    【讨论】:

      【解决方案3】:
      CREATE TABLE #MY_TABLE
      (
           ID         INT
          ,ID_FATHER  INT
          ,COL_X      INT
      )
      
      CREATE TABLE #MY_TABLE_BIS
      (
           MY_ID  INT
          ,X      VARCHAR(50)
      )
      
      CREATE TABLE #OTHER_TABLE
      (
           MY_ID  INT
          ,[ROOT] VARCHAR(50)
      )
      
      CREATE TABLE #BIG_TABLE
      (
           AN_ID  INT
      )
      go
      
      DECLARE @MAXDEPTH INT = 10
      
      ;WITH
          cte_prepare
          AS
          (
              SELECT
                   ID
                  ,ID_FATHER
                  ,TB.X
                  ,OT.[ROOT]
              FROM #MY_TABLE T
              LEFT JOIN #MY_TABLE_BIS TB
                          ON TB.MY_ID = COL_X
              LEFT JOIN #OTHER_TABLE OT
                          ON OT.MY_ID = COL_X
          ),
          cte_connect (LVL, ID, X_ALIAS, X_ALIAS_FATHER, X_ALIAS_LEAF)
          AS
          (
              SELECT 1
                  ,T.ID
                  ,CAST(CONCAT(T.[ROOT], '.C_', T.X) AS VARCHAR(MAX))
                  ,CAST(CONCAT(T.[ROOT], '.') AS VARCHAR(MAX))
                  ,CAST(T.X AS VARCHAR(30))
              FROM cte_prepare T
              WHERE T.ID_FATHER IN
                  (
                      SELECT AN_ID AS ID_FATHER
                      FROM #BIG_TABLE
                  )
      
              UNION ALL
      
              SELECT F.LVL + 1
                   ,S.ID
                   ,CAST(CONCAT(F.X_ALIAS, '.C_' + S.X) AS VARCHAR(MAX))
                   ,CAST(F.X_ALIAS AS VARCHAR(MAX))
                   ,CAST(S.X AS VARCHAR(30))
              FROM cte_prepare S
                  INNER JOIN cte_connect F
                              ON S.ID_FATHER = F.ID
              WHERE F.LVL < @MAXDEPTH
          )
      SELECT DISTINCT
           CT.X_ALIAS
          ,CT.X_ALIAS_FATHER
          ,CT.X_ALIAS_LEAF
          ,CT.LVL
      FROM cte_connect CT
      -- Uncomment this and set depth when it's greater than 100.
      --OPTION (MAXRECURSION 0) -- value between 0 and 32,767 (default is 100), 0 = unlimited
      

      另见 https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver15

      【讨论】:

        猜你喜欢
        • 2014-05-30
        • 1970-01-01
        • 2021-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-09
        • 2011-05-01
        • 2014-03-31
        相关资源
        最近更新 更多