階層データを含むテーブルがあります-次のようなものです:
childID | parentID
____________________
1 | 5
5 | 9
9 | 20
2 | 4
3 | 7
7 | 8
8 | 8
20 | 20
4 | 4
8 | 8
必要な出力:
トップfatherID
を見つける再帰CTEを作成しました。
何かのようなもの:
;WITH cte AS (
SELECT a.childID
,a.parentID
,1 AS lvl
FROM [Agent_Agents] a
WHERE a.childID = 214 //<==== value to begin with !! - thats part the problem
UNION ALL
SELECT tmp.childID
,tmp.parentID
,cte.lvl+1
FROM [Agent_Agents] tmp
INNER JOIN cte ON tmp.childID = cte.parentID
WHERE cte.childID<>cte.parentID
)
SELECT *
FROM cte
WHERE lvl = (
SELECT MAX(lvl)
FROM cte
)
問題:
explicitchildID
値を使用して(214)で始まるCTEを実行しました!したがって、214の値のみが得られます。 CTEは再帰的な部分を実行し、childIDのtopParentを見つけます。
butForEach row in the Table
-にchildID
値でCTEを実行させたい!
私はCROSS APPLY
でそれをやろうとしました:
何かのようなもの:
select * from myTable Cross Apply (
;WITH cte AS (....)
)
しかし、私見(私のテストから!!)-それは不可能です。
再帰CTEをUDFに配置するという別のアイデアには、パフォーマンスの低下があります(私たちが知っているようにudfの問題)。
実際に機能するようにこのクエリを作成するにはどうすればよいですか? (またはいくつかの近い解決策)?
これが私が試したことです
https://data.stackexchange.com/stackoverflow/query/edit/69458
あなたが探しているものがわかりませんが、これかもしれません。
;WITH c
AS (SELECT childid,
parentid,
parentid AS topParentID
FROM @myTable
WHERE childid = parentid
UNION ALL
SELECT T.childid,
T.parentid,
c.topparentid
FROM @myTable AS T
INNER JOIN c
ON T.parentid = c.childid
WHERE T.childid <> T.parentid)
SELECT childid,
topparentid
FROM c
ORDER BY childid
これは answer by marc_s と同じですが、テーブル変数を使用する点と、marc_sによる回答があるルートノードにchildID = parentID
があるという事実が異なります。ルートノードにはparent_ID = null
があります。私の意見では、ルートノードにはparent_ID = null
を使用することをお勧めします。
このようなことはできませんか?
;WITH cte AS (....)
SELECT
*
FROM
cte
CROSS APPLY
dbo.myTable tbl ON cte.XXX = tbl.XXX
置く CROSS APPLY
after CTE定義-CTEを参照する1つのSQLステートメントに。それはうまくいきませんか?
OR:-ロジックを反転します-「トップダウン」CTEを実行します。これは、最初にトップレベルノードを選択し、次に階層を反復処理します。このようにして、再帰CTEの最初の部分で「トップレベルの父親」を簡単に判別できます。次のようになります。
;WITH ChildParent AS
(
SELECT
ID,
ParentID = ISNULL(ParentID, -1),
SomeName,
PLevel = 1, -- defines level, 1 = TOP, 2 = immediate child nodes etc.
TopLevelFather = ID -- define "top-level" parent node
FROM dbo.[Agent_Agents]
WHERE ParentID IS NULL
UNION ALL
SELECT
a.ID,
ParentID = ISNULL(a.ParentID, -1),
a.SomeName,
PLevel = cp.PLevel + 1,
cp.TopLevelFather -- keep selecting the same value for all child nodes
FROM dbo.[Agent_Agents] a
INNER JOIN ChildParent cp ON r.ParentID = cp.ID
)
SELECT
ID,
ParentID,
SomeName,
PLevel,
TopLevelFather
FROM ChildParent
これにより、ノードは次のようになります(サンプルデータに基づいて、わずかに拡張されています)。
ID ParentID SomeName PLevel TopLevelFather
20 -1 Top#20 1 20
4 -1 TOP#4 1 4
8 -1 TOP#8 1 8
7 8 ChildID = 7 2 8
3 7 ChildID = 3 3 8
2 4 ChildID = 2 2 4
9 20 ChildID = 9 2 20
5 9 ChildID = 5 3 20
1 5 ChildID = 1 4 20
これで、このCTE出力から特定の子ノードを選択すると、子の「レベル」とその最上位の親ノードなど、必要なすべての情報が常に取得されます。
私はまだあなたの質問をさらに調べる時間がなく、あなたの問題を理解したかどうかはわかりませんが、このsvfを使用してトップの父親のIDを取得できませんでしたか?
CREATE FUNCTION [dbo].[getTopParent] (
@ChildID INT
)
RETURNS int
AS
BEGIN
DECLARE @result int;
DECLARE @ParentID int;
SET @ParentID=(
SELECT ParentID FROM ChildParent
WHERE ChildID = @ChildID
)
IF(@ParentID IS NULL)
SET @result = @ChildID
ELSE
SET @result = [dbo].[getTopParent](@ParentID)
RETURN @result
END
次に、次の方法で各上位の親を見つけることができるはずです。
SELECT ChildID
, [dbo].[getTopParent](ChildID) AS TopParentID
FROM ChildParent
select distinct
a.ChildID,a.ParentID,
--isnull(nullif(c.parentID,b.parentID),a.parentID) as toppa,
B.parentID
--,c.parentID
,isnull(nullif(d.parentID,a.parentID),c.parentID) as toppa1,a.name
from myTable a
inner join myTable c
on a.parentID=c.parentID
inner join myTable b
on b.childID=a.parentID
inner join myTable d
on d.childID=b.parentID
CTEなしの式を使用してから、結合を使用して子の親をステップ実行するステップを取得しました。さらに重要な共通テーブル式は、サーバー2000ではなくSQL Server 2005で導入されたため、結合を使用して値を取得するのが基本的な方法です。子値の親ID
select dbo.[fn_getIMCatPath](8)
select Cat_id,Cat_name,dbo.[fn_getIMCatPath](cat_id) from im_category_master
Create FUNCTION [dbo].[fn_getIMCatPath] (@ID INT)
returns NVARCHAR(1000)
AS
BEGIN
DECLARE @Return NVARCHAR(1000),
@parentID INT,
@iCount INT
SET @iCount = 0
SELECT @Return = Cat_name,
@parentID = parent_id
FROM im_category_master
WHERE [cat_id] = @ID
WHILE @parentID IS NOT NULL
BEGIN
SELECT @Return = cat_name + '>' + @Return,
@parentID = parent_id
FROM im_category_master
WHERE [cat_id] = @parentID
SET @iCount = @iCount + 1
IF @parentID = -1
BEGIN
SET @parentID = NULL
END
IF @iCount > 10
BEGIN
SET @parentID = NULL
SET @Return = ''
END
END
RETURN @Return
END
このサンプルデータとそれぞれのSQLを検討して、子レコードとその最上位の親にアクセスします。
SQLコード:
;WITH c AS (
SELECT Id, Name, ParentId as CategoryId,
Id as MainCategoryId, Name AS MainCategory
FROM pmsItemCategory
WHERE ParentId is null
UNION ALL
SELECT T.Id, T.Name, T.ParentId, MainCategoryId, MainCategory
FROM pmsItemCategory AS T
INNER JOIN c ON T.ParentId = c.Id
WHERE T.ParentId is not null
)
SELECT Id, Name, CategoryId, MainCategoryId, MainCategory
FROM c
order by Id