web-dev-qa-db-ja.com

親のすべての子(子孫)を取得するCTE

私は私に頭痛を与えているこの問題を抱えています...

たとえば、数千行のテーブルがあり、テーブルの構造は親->子の関係で構成されているとします。

関係は6レベルまで上がることができます。以下はテーブル構造のサンプルです。

ProductId | ParentId | Levels
1174           0        1174
311           1174      311, 1174
1186          311       1186, 311, 1174
448           1186      448, 1186, 311, 1174
3365          448       3365, 448, 1186, 311, 1174

テーブル全体をループして関係を取得し、「レベル」列を保存するプロセスを取得しました。このプロセスは(ループが原因で)非常に遅く、関係を取得するためにいくつかのcteを試行しましたが、誤って失敗しました。

これまでのところ、このcteを試しましたが、期待していたことはできません。また、行を複製しているようです...

;With Parents(ProductId, ParentId, Levels)
As(
  Select ProductId, ParentId, Levels
  From Products
  Where ParentId = 0 
  Union All
  Select p.ProductId, p.ParentId, p.Levels
  From Products p
  Join Parents cte On cte.ProductId = p.ParentId
)
Select *
From Parents

先に述べたように、テーブルをループするプロセスを取得しました。そのプロセスは機能しますが、最大30分かかる場合があります。私の質問は、これを行うより良い方法があるかどうかです。私はCTEでそれができることを知っていますが、私はそれを吸っています、また、レベルの列を計算してテーブルで更新する必要があります、それは可能ですか?

ここに Sqlfiddle があります。

15
Sam Ccp

これはそれを行うはずです:

WITH MyTest as
(
  SELECT P.ProductID, P.ParentID, CAST(P.ProductID AS VarChar(Max)) as Level
  FROM Products P
  WHERE P.ParentID = 0

  UNION ALL

  SELECT P1.ProductID, P1.ParentID, CAST(P1.ProductID AS VarChar(Max)) + ', ' + M.Level
  FROM Products P1  
  INNER JOIN MyTest M
  ON M.ProductID = P1.ParentID
 )
SELECT * From MyTest

そして、これが更新された SQL Fiddle です。

また、CTEのヘルプについては このリンク を確認してください...

これがうまくいくことを願っています!

38
John Bustos
;With Parents(ProductId, ParentId, Level, levels)
As(
  Select ProductId, ParentId, 0, 
     cast(ltrim(str(productId,8,0)) as varchar(max))
  From Products
  Where ParentId = 0 
  Union All
  Select p.ProductId, p.ParentId, 
      par.Level + 1,
      cast( levels + ', ' + ltrim(str(productId,8,0)) as varchar(max))
  From Products p
     Join Parents par
        On par.ProductId = p.ParentId
  )
  Select * From Parents
  Order By Level
2
Charles Bretana