SQL Serverで再帰的な自己結合を行う最も簡単な方法は何ですか?このようなテーブルがあります:
PersonID | Initials | ParentID
1 CJ NULL
2 EB 1
3 MB 1
4 SW 2
5 YT NULL
6 IS 5
そして、特定の人から始まる階層にのみ関連するレコードを取得できるようにしたいと思います。したがって、PersonID = 1でCJの階層を要求すると、次のようになります。
PersonID | Initials | ParentID
1 CJ NULL
2 EB 1
3 MB 1
4 SW 2
EBの場合は次のようになります。
PersonID | Initials | ParentID
2 EB 1
4 SW 2
私はこれに固執していますが、多数の結合に基づいた固定深さの応答とは別にそれを行う方法を考えることはできません。多くのレベルを持たないため、これは起こりますが、適切に行いたいと思います。
ありがとう!クリス。
WITH q AS
(
SELECT *
FROM mytable
WHERE ParentID IS NULL -- this condition defines the ultimate ancestors in your chain, change it as appropriate
UNION ALL
SELECT m.*
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
順序付け条件を追加することにより、ツリーの順序を保持できます。
WITH q AS
(
SELECT m.*, CAST(ROW_NUMBER() OVER (ORDER BY m.PersonId) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
FROM mytable m
WHERE ParentID IS NULL
UNION ALL
SELECT m.*, q.bc + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.PersonID) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
ORDER BY
bc
ORDER BY
条件では、兄弟の順序を変更できます。
CTEを使用すると、このようにできます
DECLARE @Table TABLE(
PersonID INT,
Initials VARCHAR(20),
ParentID INT
)
INSERT INTO @Table SELECT 1,'CJ',NULL
INSERT INTO @Table SELECT 2,'EB',1
INSERT INTO @Table SELECT 3,'MB',1
INSERT INTO @Table SELECT 4,'SW',2
INSERT INTO @Table SELECT 5,'YT',NULL
INSERT INTO @Table SELECT 6,'IS',5
DECLARE @PersonID INT
SELECT @PersonID = 1
;WITH Selects AS (
SELECT *
FROM @Table
WHERE PersonID = @PersonID
UNION ALL
SELECT t.*
FROM @Table t INNER JOIN
Selects s ON t.ParentID = s.PersonID
)
SELECT *
FROm Selects
大きなテーブルの変更を伴うQuassnoiクエリ。 10以上の子を持つ親:str(5)としてrow_number()としてフォーマット
WITH q AS ( SELECT m。*、CAST(str(ROW_NUMBER()OVER(ORDER BY m.ordernum)、5)AS VARCHAR(MAX))COLLATE Latin1_General_BIN AS bc FROM #tm WHERE ParentID = 0 UNION ALL SELECT m。*、q.bc + '。' + str(ROW_NUMBER()OVER (PARTITION BY m.ParentID ORDER BY m.ordernum)、5)COLLATE Latin1_General_BIN FROM #tm JOIN q ON m.parentID = q.DBID ) SELECT * FROM q ORDER BY bc
SQL 2005以降では、CTEが、示されている例に従って進むための標準的な方法です。
SQL 2000、UDFを使用して実行できます-
CREATE FUNCTION udfPersonAndChildren
(
@PersonID int
)
RETURNS @t TABLE (personid int, initials nchar(10), parentid int null)
AS
begin
insert into @t
select * from people p
where personID=@PersonID
while @@rowcount > 0
begin
insert into @t
select p.*
from people p
inner join @t o on p.parentid=o.personid
left join @t o2 on p.personid=o2.personid
where o2.personid is null
end
return
end
(これは2005年に機能しますが、それは標準的な方法ではありません。作業が簡単な方法であることがわかった場合は、それで実行してください)
本当にSQL7でこれを行う必要がある場合、sprocで上記のことを大まかに行うことができますが、選択できませんでした-SQL7はUDFをサポートしていません。
以下をチェックして、CTE再帰の概念を理解してください。
DECLARE
@startDate DATETIME,
@endDate DATETIME
SET @startDate = '11/10/2011'
SET @endDate = '03/25/2012'
; WITH CTE AS (
SELECT
YEAR(@startDate) AS 'yr',
MONTH(@startDate) AS 'mm',
DATENAME(mm, @startDate) AS 'mon',
DATEPART(d,@startDate) AS 'dd',
@startDate 'new_date'
UNION ALL
SELECT
YEAR(new_date) AS 'yr',
MONTH(new_date) AS 'mm',
DATENAME(mm, new_date) AS 'mon',
DATEPART(d,@startDate) AS 'dd',
DATEADD(d,1,new_date) 'new_date'
FROM CTE
WHERE new_date < @endDate
)
SELECT yr AS 'Year', mon AS 'Month', count(dd) AS 'Days'
FROM CTE
GROUP BY mon, yr, mm
ORDER BY yr, mm
OPTION (MAXRECURSION 1000)