복붙노트

[SQL] 재귀는 자체 조인 할 수있는 가장 간단한 방법은?

SQL

재귀는 자체 조인 할 수있는 가장 간단한 방법은?

재귀 수행하는 가장 간단한 방법은 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

나는 약간의 조인 무리를 기반으로 고정 깊이 응답에서 떨어져 작업을 수행하는 방법을 생각할 수 없다이 캔에 붙어 있어요. 우리는 많은 수준이되지 않습니다하지만 난 그것을 제대로 할 싶습니다 때문에 그런 일이 이것은 할 것이다.

감사! 크리스.

해결법

  1. ==============================

    1.

    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
    

    조건에 의해 순서를 변경하여 당신은 형제의 순서를 변경할 수 있습니다.

  2. ==============================

    2.열팽창 계수를 사용하면 당신은이 방법을 수행 할 수 있습니다

    열팽창 계수를 사용하면 당신은이 방법을 수행 할 수 있습니다

    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
    
  3. ==============================

    3.큰 테이블에 대한 변경이있는 Quassnoi 쿼리. 다음 10 개의 차일 부모 : STR로 포맷하기 (5) ROW_NUMBER ()

    큰 테이블에 대한 변경이있는 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
    
    
  4. ==============================

    4.SQL 2005 이상은, 열팽창 계수가 표시의 예에 따라 이동하는 표준 방법입니다.

    SQL 2005 이상은, 열팽창 계수가 표시의 예에 따라 이동하는 표준 방법입니다.

    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를 지원하지 않습니다.

  5. ==============================

    5.(가) CTE의 재귀의 개념을 이해하는 데 도움이되는 다음 확인

    (가) 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)
    
  6. from https://stackoverflow.com/questions/1757260/simplest-way-to-do-a-recursive-self-join by cc-by-sa and MIT license