재귀적인 자기 조인을하는 가장 간단한 방법?
-
20-09-2019 - |
문제
SQL Server에서 재귀적인 자체 접합을하는 가장 간단한 방법은 무엇입니까? 나는 다음과 같은 테이블이 있습니다.
PersonID | Initials | ParentID
1 CJ NULL
2 EB 1
3 MB 1
4 SW 2
5 YT NULL
6 IS 5
그리고 나는 특정 사람으로 시작하는 계층 구조와 관련된 레코드를 얻을 수 있기를 원합니다. 따라서 CJ의 계층 구조를 PersonID = 1으로 요청하면 다음을 얻을 수 있습니다.
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 #t m 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 #t m JOIN q ON m.parentID = q.DBID ) SELECT * FROM q ORDER BY bc
SQL 2005 이상, CTE는 표시된 예제에 따라 진행되는 표준 방법입니다.
SQL 2000, UDFS를 사용하여 할 수 있습니다.
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)
제휴하지 않습니다 StackOverflow