如何将while循环转换为CTE

时间:2019-07-17 09:40:48

标签: sql sql-server common-table-expression recursive-query cyclic-reference

我们有一个存储过程,在该过程中,我们使用while循环,每次将任何孩子的孩子作为父母的孩子插入。现在,此循环要花费11个小时以上才能完成。那么有人可以帮助我将while循环转换为CTE吗?哪个会减少执行时间?还有其他方法可以提高以下查询的性能吗?您可以从下面的链接中找到架构,如果访问下面的链接有任何问题,请使用下面的查询。

CREATE TABLE Temptbl (
    ParentNumber Varchar(9) ,
    ChildNumber Varchar(9)
);

DECLARE @lastupdate INTEGER
  SET @lastupdate = 1

    WHILE (@lastupdate > 0)
BEGIN

  INSERT INTO Temptbl
  SELECT DISTINCT
         a.ParentNumber,
         b.ChildNumber
    FROM Temptbl a,
         Temptbl b
   WHERE a.ChildNumber = b.ParentNumber
     AND NOT EXISTS (SELECT 1
                       FROM Temptbl c
                      WHERE c.ParentNumber = a.ParentNumber
                        AND c.ChildNumber  = b.ChildNumber)

  SET @lastupdate = @@ROWCOUNT

END

Fiddle link

2 个答案:

答案 0 :(得分:0)

尝试以下查询。可能会对您有帮助。

;with cte as (
 SELECT DISTINCT
         a.ParentNumber,
         b.ChildNumber, ROW_NUMBER()over(order by a.ParentNumber) as RNO
    FROM Temptbl a,
         Temptbl b
   WHERE a.ChildNumber = b.ParentNumber
     AND NOT EXISTS (SELECT 1
                       FROM Temptbl c
                      WHERE c.ParentNumber = a.ParentNumber
                        AND c.ChildNumber  = b.ChildNumber)
)
INSERT INTO Temptbl
select ParentNumber, ChildNumber from cte
where RNO>0

答案 1 :(得分:0)

如果需要递归,这里是一个版本,即如果给定A-> B,B-> C,C-> D,则期望A-> C和A-> D

DROP TABLE IF EXISTS Temptbl
CREATE TABLE Temptbl
(
    ParentNumber VARCHAR(9),
    ChildNumber VARCHAR(9)
)

INSERT INTO Temptbl (ParentNumber, ChildNumber) 
VALUES ('a1','b1'), ('b1','c1'),
       ('a2','b2'), ('b2','c2'),
       ('a3','b3'), ('b3','c1'),
       ('c1','d1');

-- expect insert of 
-- (a1, c1) via b1
-- (a1, d1) via b1 -> c1
-- (a2, c2) via b2
-- (a3, c1) via b3 
-- (a3, d1) via b3 -> c1
-- (a3, d1) via b3 -> c1
-- (b3, d1) via c1

WITH Tree(ParentNumber,ChildNumber) AS
(
    --Initialization
    SELECT ParentNumber, ChildNumber
    FROM Temptbl
        UNION ALL
    SELECT t1.ParentNumber,t2.ChildNumber AS ChildNumber
    FROM Temptbl t1
    INNER JOIN Temptbl t2 ON t1.ChildNumber = t2.ParentNumber 
        UNION ALL
    --Recursive execution 
    SELECT Tree.ParentNumber,t.ChildNumber
    FROM Temptbl t INNER JOIN Tree ON Tree.ChildNumber = t.ParentNumber 
)
INSERT INTO Temptbl
(
    ParentNumber,
    ChildNumber
)
SELECT DISTINCT
    Tree.ParentNumber,
    Tree.ChildNumber
FROM tree 
WHERE NOT EXISTS (SELECT * FROM Temptbl t WHERE t.ParentNumber = tree.ParentNumber AND t.ChildNumber = tree.ChildNumber)
OPTION (MAXRECURSION 5); -- change 5 to the maximum depth of hierarchy you need it to handle

SELECT * FROM dbo.Temptbl