代码之家  ›  专栏  ›  技术社区  ›  Tim Schmelter

递归CTE以查找父记录

  •  6
  • Tim Schmelter  · 技术社区  · 14 年前

    首先,我必须承认,我不太熟悉SQL Server的 recursive cte's

    我有一个表 tabdata 。它的pk名为 iddata,有一个自引用fk fidata。

    因此,fidata引用父记录,并从tabdata中选择“*”,其中iddata=fidata 返回父记录的所有数据。这是简单而快速的。但是,如何让所有的父母按照自然顺序从一个给定的记录中获得呢? 假设有一个子级(iddata=4)有3个父级(第一个父级是iddata=3的记录):。

    iddata fidata
    4 3
    3 2
    2 1
    1空
    < /代码> 
    
    

    我认为递归CTE是一种可行的方法,但它的语法不太好。 那么,实现返回所有父级的CTE的正确方法是什么呢?

    我尝试了以下方法,但它给了我错误的结果(3,4而不是3,2,1): (为了测试它,我为我和你创建了一个临时表)

    if(not exists(select*from information\u schema.tables where table\u schema='dbo'and table\u name='tabdata\u temp'))
    开始
    创建表[dbo]。[tabdata_temp](
    [iddata][int]不为空,
    [fidata][int]空,
    约束[pk_tabdata_temp]主键聚集
    (
    [IDDATA] ASC
    )使用(pad_index=off,statistics_norecompute=off,ignore_dup_key=off,allow_row_locks=on,allow_page_locks=on)
    ;
    
    更改表[dbo]。[tabdata_temp]和check add约束[fk_tabdata_temp]外键([fidata])
    引用[dbo]。[tabdata_temp]([iddata]);
    更改表[dbo]。[tabdata_temp]检查约束[fk_tabdata_temp];
    
    插入[dbo]。[tabdata_temp](iddata,fidata)值(1,空);
    插入[dbo]。[tabdata_temp](iddata,fidata)值(2,1);
    插入[dbo]。[tabdata_temp](iddata,fidata)值(3,2);
    插入[dbo]。[tabdata_temp](iddata,fidata)值(4,3);
    结束
    
    /*这里是(不工作的)递归CTE*/
    声明@fidata int;
    设置@fidata=3;
    具有预先声明(iddata、fidata)
    as(
    选择parent.iddata,parent.fidata
    从tabdata_temp父级
    其中parent.iddata=@fidata
    
    联合所有
    
    选择child.iddata,child.fidata
    从tabdata_temp child
    parent.iddata=child.fidata上的内部联接previouslaims parent
    )
    选择IDDATA
    来自先前的主张;
    /*递归CTE结束*/
    
    
    删除表[dbo]。[tabdata_temp];
    < /代码> 
    
    

    提前谢谢。recursive CTE's但我认为这是最好的方法。

    我有一张桌子tabData. 其PK被命名为idData有一个自参考FKfiData.

    Schema

    所以fidata引用父记录SELECT * FROM tabData WHERE idData=fiData返回父级的所有数据。这是简单而快速的。但是,如何让所有的父母按照自然顺序从一个给定的记录中获得呢? 假设有一个孩子(iddata=4)有3个父母(第一个父母是iddata=3的记录):

    idData    fiData 
     4          3     
     3          2     
     2          1    
     1          NULL    
    

    我认为递归CTE是一种可行的方法,但它的语法不太好。 那么,实现返回所有父级的CTE的正确方法是什么呢?

    我尝试了以下方法,但它给了我错误的结果(3,4而不是3,2,1): (为了测试它,我为我和您创建了一个临时表)

    IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND  TABLE_NAME = 'tabData_Temp'))
    BEGIN
     CREATE TABLE [dbo].[tabData_Temp](
      [idData] [int] NOT NULL,
      [fiData] [int] NULL,
       CONSTRAINT [PK_tabData_Temp] PRIMARY KEY CLUSTERED 
      (
       [idData] ASC
      )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)
     );
    
     ALTER TABLE [dbo].[tabData_Temp]  WITH CHECK ADD  CONSTRAINT [FK_tabData_Temp] FOREIGN KEY([fiData])
     REFERENCES [dbo].[tabData_Temp] ([idData]);
     ALTER TABLE [dbo].[tabData_Temp] CHECK CONSTRAINT [FK_tabData_Temp];
    
     INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(1,NULL);
     INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(2,1);
     INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(3,2);
     INSERT INTO [dbo].[tabData_Temp](idData,fiData)VALUES(4,3);
    END
    
    /* here comes the (not working) recursive CTE */
    Declare @fiData int;
    SET @fiData = 3;
    WITH PreviousClaims(idData,fiData) 
    AS(
         SELECT parent.idData,parent.fiData
         FROM tabData_temp parent
         WHERE parent.idData = @fiData
    
         UNION ALL
    
         SELECT child.idData,child.fiData
         FROM tabData_temp child
         INNER JOIN PreviousClaims parent ON parent.idData = child.fiData
    )
    SELECT idData
    FROM PreviousClaims;
    /* end of recursive CTE */
    
    
    DROP TABLE [dbo].[tabData_Temp];
    

    提前谢谢。

    2 回复  |  直到 14 年前
        1
  •  7
  •   Kirk Woll    14 年前

    改为:

    INNER JOIN PreviousClaims parent ON parent.fiData = child.idData
    

    给了我你想要的结果。

        2
  •  6
  •   Gabriel McAdams    14 年前

    你的连接是向后的。

    改变这个

    INNER JOIN PreviousClaims parent ON parent.idData= child.fiData 
    

    对此

    INNER JOIN PreviousClaims parent ON parent.fiData = child.idData