3

私はこのテーブルを持っています:

Categories( CatId, Name, ParentId NULL )

...これは再帰的であるため、各カテゴリは親カテゴリに名前を付けることができ、親カテゴリには親があります。そのようです:

1, "Sports", NULL
2, "Football", 1
3, "Golf", 1
4, "Handegg", 2
5, "Sex", NULL
6, "On the beach", 5

少し前に、CTEを使用して、次のようにカテゴリの親に対して再帰的なルックアップを実行しました。

WITH Categories(CatId, Name, ParentId, n) AS (
    SELECT CatId, Name, ParentId, 1
    FROM Categories
    WHERE CatId = @categoryId

    UNION ALL

    SELECT c1.CatId, c1.Name, c1.ParentId, c2.n + 1
    FROM Categories AS c1
         INNER JOIN Categories AS c2 ON c1.CatId = c2.ParentId
)

しかし、私は考えていました、それをWHILEクエリとして言い換えることはできませんか?

DECLARE @ret TABLE( CatId, Name, ParentId )

DECLARE @tCatId int
DECLARE @tName nvarchar(255)
DECLARE @tParentId int NULL

SELECT @tCatId = CatId, @tName = Name, @tParentId = ParentId
FROM Categories
WHERE CatId = @categoryId

WHILE( @tParentId IS NOT NULL ) BEGIN
    INSERT INTO @ret ( CatId, Name, ParentId ) VALUES ( @tCatId, @tName, @tParentId )

    SELECT @tCatId = CatId, @tName = Name, @tParentId = ParentId
    FROM Categories
    WHERE CatId = @tParentId
END

SELECT @ret

明らかに、それは端が少し荒く(最初の行のParentIdがNULLのときに完了しないなど)、テストできませんでした(SQL Serverが再構築のためにダウンしているため)が、確かに同じように正しいです?

4

3 に答える 3

5

これは意味的には機能しますが、CTEは不変の論理的な結果セットを表すため、一般的にプログラミングに適しています。whileループは、実行モデルを強制的に指示します。そのため、正しく管理するのはもう少し手間がかかります。

CTEが速くなる可能性は十分にあります。内部的にはwhileループの形式が含まれていますが、そのループはクエリ実行パイプラインの奥深くにあります。T-SQLループよりもはるかに高速です。また、それは単一のステートメントです。whileループは、多くのステートメントを実行します。SQL Serverには、ステートメントごとのオーバーヘッドがわずかにあります(たとえそれがselect null)であるとしても。

つまり、whileループを使用すると、柔軟性と制御性が向上する場合があります。

おそらく、最初にCTEを使用して要件を解決するようにしてください。命令型制御フローは、具体的な理由でwhileループの方が優れたソリューションであることに気付いた場合(または予測できる場合)にのみ使用してください。

于 2012-09-23T08:59:56.300 に答える
1

CTEは、複雑なクエリを記述できる一時的な結果セットを表すために使用されます。

WITH DerviedTable (<Column>) AS (SELECT query to derive a table from one or more tables)
<A complex SELECT query that uses the DerviedTable one or more times>

CTEがない場合は、JOINSで参照する必要があるすべての場所でその派生テーブルを定義する必要があります。

再帰を使用したCTEはUNION ALL、ベースの再帰ロジックを確実に補完WHILEしますが、ご覧のとおり、TSQLを記述して、ベースメンバーと再帰メンバーを定義するだけの手間が省けます。

MSSQL Serverに関する以前のプロジェクトの1つで、SQL Server 2005に移行したときに、このようなWHILEベースの再帰をすべてCTEに積極的に置き換え、CTE定義にテーブル変数が含まれるデッドロック状態に陥りました。これが最近のバージョンで修正されているかどうかはわかりませんが、共有する価値があると考えています。

于 2012-09-23T05:50:37.997 に答える
0

どちらも正しくない

最初に欠落している
c2.CatId = @categoryId

2 番目
の WHERE CatId = @tParentId

于 2012-09-23T12:53:32.067 に答える