以下の表に、レベルの数が異なる階層があります。この例では、7つのレベルのサブセットを選択しました。
L_Key Parent Level P_Key
-------------------------
1393 NULL 0 2
1399 1393 1 325
4485 1399 2 NULL
4505 4485 3 NULL
5066 4505 4 NULL
6121 5066 5 NULL
5068 6121 6 NULL
私の目標は、NULLでない親のプロパティを取得することです。したがって、この場合、これは返されるはずです。
L_Key Parent Level P_Key
-------------------------
1393 NULL 0 2
1399 1393 1 325
4485 1399 2 325
4505 4485 3 325
5066 4505 4 325
6121 5066 5 325
5068 6121 6 325
これは私がこれまでに試したことです。
;WITH CTE AS (
SELECT
m.Functional_Location_Key
,m.Parent_Key
,m.Level
,m.Property_Key
FROM #MappingPartOne m
WHERE m.Functional_Location_Key IN (6121,5068,5066,4505,4485,1399,1393)
UNION ALL
SELECT
t.Functional_Location_Key
,t.Parent_Key
,t.Level
,t.Property_Key
FROM CTE t
JOIN #MappingPartOne b ON b.Parent_Key = t.Functional_Location_Key
)
SELECT
Functional_Location_Key
,Parent_Key
,Level
,Property_Key
FROM CTE
option (maxrecursion 0)
これを除いて、無限ループが発生します。
ご協力ありがとうございました。
テスト用にテーブル変数を設定しました
DECLARE @MappingPartOne TABLE (
Functional_Location_Key int,
Parent_Key int,
Level int,
Property_Key int
)
INSERT INTO @MappingPartOne VALUES (1393, NULL, 0, 2)
INSERT INTO @MappingPartOne VALUES (1399, 1393, 1, 325)
INSERT INTO @MappingPartOne VALUES (4485, 1399, 2, NULL)
INSERT INTO @MappingPartOne VALUES (4505, 4485, 3, NULL)
INSERT INTO @MappingPartOne VALUES (5066, 4505, 4, NULL)
INSERT INTO @MappingPartOne VALUES (6121, 5066, 5, NULL)
INSERT INTO @MappingPartOne VALUES (5068, 6121, 6, NULL)
追加できるレコードが常に見つかるので、クエリは無限ループを実行しています。これは、クエリの後半(UNION ALLの後)に追加する行が、クエリの前半にある正確な行であるためです。 SELECTリストでCTE
ではなく_@MappingPartOne
_テーブルの列を使用する場合、無限ループは発生しません。 wantは得られませんが、無限ループは得られません。
私が正しく理解している場合、行の_Property_Key
_がNULLの場合、行の親で使用されているのと同じ_Property_Key
_値を使用する必要があります。つまり、最も近い祖先の_Property_Key
_、その値はNULLではありません。例:_Functional_Location_Key
_ = 4505の行にNULLではなく_Property_Key
_ = 9978が含まれる場合、その子孫(_Functional_Location_Key
_ 5066、6121、および5068)は_Property_Key
_ = 9978を表示します。
これを行うには、クエリにいくつかの変更を加える必要があります。
まず、前述のように、CTEの2番目の部分は、CTE
ではなく_@MappingPartOne
_テーブルから列を出力する必要があります。ただし、これにより、行の複数のコピーが得られます。
各行の単一のコピーを取得するには、CTEを異なる方法で開始する必要があります。最初は、CTEの最初の部分に表示する行のリストを明示的に提供しています。ただし、2番目の部分では、前の反復からの各行の子孫を取り込みます。最初の部分に、含めた他の行の子孫である行を含めたので、行を反復するときに重複が発生します。
代わりに、最終的な親行(他の行の子孫ではない行)のみを指定する必要があります。つまり、_Parent_Key
_がNULLである行(この場合は行)です。
次のステップは、行の_Property_Key
_がNULLかどうかを確認し、(そうであれば)親と同じ値を使用することです。 its親の_Property_Key
_を使用するため、親の_Property_Key
_もNULLであるかどうかは関係ありません。データを反復するたびに、現在の行(_@MappingPartOne
_から)とその親(CTE
から)が得られます。したがって、単に_@MappingPartOne.Property_Key
_を使用する代わりに、それがNULLかどうかを確認します。そうでない場合は、それを使用します。そうである場合は、_CTE.Property_Key
_を使用します。
したがって、これにより次のクエリが得られます。
_WITH CTE AS (
SELECT
m.Functional_Location_Key
,m.Parent_Key
,m.Level
,m.Property_Key
FROM #MappingPartOne m
WHERE m.Parent_Key IS NULL
UNION ALL
SELECT
b.Functional_Location_Key
,b.Parent_Key
,b.Level
,COALESCE(b.Property_Key, t.Property_Key) as Property_Key
FROM CTE t
JOIN #MappingPartOne b ON b.Parent_Key = t.Functional_Location_Key
)
SELECT
Functional_Location_Key
,Parent_Key
,Level
,Property_Key
FROM CTE
;
_
この動作は this SQLFiddle link で確認できます。
(これまでに使用したことがない場合、COALESCE()
はISNULL()
関数のように機能します。2つの潜在的な利点があります。3つ以上の引数を指定できるため、この場合、最初の非NULL引数、またはすべてがNULLの場合はNULL、それはANSI標準の一部であるため、他のSQL方言に移植できる可能性が高くなります。
CTEの最初の部分でWHERE
句の条件を変更して、特定の行を_Functional_Location_Key
_で選択する場合、残りの階層を無視して、任意の行とその子孫をプルアップできます。必要な場合に備えて。
コメントごとに、親を持つ最高レベルの祖先からの_Property_Key
_(roe 1393からではなく、行1399から)をNULLを持つすべての子孫のデフォルトとして表示するように見えます_Property_Key
_ 。
これを行うには、CTEに列を追加するだけで済みます。
_WITH CTE AS (
SELECT
m.Functional_Location_Key
,m.Parent_Key
,m.Level
,m.Property_Key
,NULL as Top_Property_Key
FROM MappingPartOne m
WHERE m.Parent_Key IS NULL
UNION ALL
SELECT
b.Functional_Location_Key
,b.Parent_Key
,b.Level
,COALESCE(b.Property_Key, t.Top_Property_Key) as Property_Key
,COALESCE(t.Top_Property_Key, b.Property_Key) as Top_Property_Key
FROM CTE t
JOIN MappingPartOne b ON b.Parent_Key = t.Functional_Location_Key
)
SELECT
Functional_Location_Key
,Parent_Key
,Level
,Property_Key
FROM CTE
;
_
新しい列は_Top_Property_Key
_です。最初は、最上位の親を見ています。これをデフォルトとして使用したくないので、この1つの行の値をNULLに設定しました。 CTEの2番目の部分では、確立された_Top_Property_Key
_が現在NULLでない場合はデフォルトとして使用し、それ以外の場合は現在の親行の_Property_Key
_を使用します。 _Top_Property_Key
_にNULL以外の値が割り当てられている行があると、そのすべての子の値が保持されます。
最後に、各行の_Property_Key
_のCOALESCE
を変更して、_t.Top_Property_Key
_(直接の親のプロパティキー値)ではなく、新しい列_t.Property_Key
_を使用します。
これは、新しい機能を備えた更新済みの SQLFiddle link です。
注:最上位の親の_Property_Key
_をそのすべての子のデフォルトとして使用する場合は、CTEの最初の部分でNULLの代わりに_Top_Property_Key
_を_Property_Key
_に設定します。
_ ,m.Property_Key as Top_Property_Key
_