2013-06-19 2 views
1

원래 대체 된 행을 통해 다음과 같은 구조를 가진 사용자 라이센스 테이블하게하려면 :재귀 SQL은 내가 마이크로 소프트 SQL Server 2008의 T/SQL을 사용하고

LicenceID (PK, uniqueidentifier, not null) 
SupersededID (FK, uniqueidentifier, not null) 
…other licence related columns 

사용자가 자신의 라이센스 키를 업그레이드의 SupersededID을 원래의 LicenceID로 채워집니다. 이것은 여러 번 발생할 수 있으므로 발행 된 첫 번째 라이센스에 대한 추적이 항상있을 것입니다. 또한 라이센스 키가 절대로 대체 될 수 없습니다.

내가 가지고있는 어려움은 라이센스 테이블의 모든 행을 쿼리하고 각각에 대한 최초의 원래 라이센스 키를 추출 할 수 있어야한다는 것입니다.

내가이 재귀 적으로이 라인을 따라 WITH 방법, 뭔가를 사용하여 쿼리를 호출하여 달성 할 수 있다고 생각하지만, 나는 개념에 완전히 명확하지 않다 .. 이것은 내가 지금까지 무엇을 가지고 :

 


WITH c 
    AS (SELECT SupersededByID, 
       LicenceID, 
       LicenceID AS topParentID 
     FROM Licence 
     where SupersededBy IS NOT NULL 
     UNION ALL 
     SELECT l.SupersededBy, 
       l.LicenceID, 
       c.topparentid 
     FROM Licence AS l 
       INNER JOIN c 
         ON l.id = c.SupersededByID 
     WHERE T.SupersededByID IS NOT NULL) 

SELECT * 
FROM c 
+0

SCD 유형 2 테이블을 고려하셨습니까? http://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_II 이렇게하면 재귀를 피할 수 있습니다. – gbn

답변

2

재귀의 경우 SupersededById = NULL 인 루트 레코드로 시작해야합니다. 이것들은 추적 할 현재 라이센스를 제공합니다.

그래서 기본적인 재귀 쿼리는 다음과 같이 진행됩니다

WITH c AS 
(
    SELECT SupersededById, 
      LicenceId, 
      LicenceId AS BaseId, 
      1 as Level 
    FROM Licence 
    WHERE SupersededById IS NULL 
    UNION ALL 
    SELECT l.SupersededById, 
      l.LicenceId, 
      c.BaseId, 
      c.Level + 1 as Level 
    FROM Licence AS l 
      INNER JOIN c ON l.SupersededById = c.LicenceId 
) 
SELECT * FROM c 

이 당신에게 두 개의 추가 열이있는 모든 레코드를 제공합니다 : 레벨 열 당신이 대체 라이센스로 돌아갈 때마다 올라갑니다. BaseId는 라이센스 트랙에서 동일하게 유지되는 상수입니다.

그래서 부속 함께 할 수있는 각 BaseId에 대한 최대 수준으로 기록을 찾아 데이터의 집합 :

WITH c AS 
(
    SELECT SupersededById, 
      LicenceId, 
      LicenceId AS BaseId, 
      1 as Level 
    FROM Licence 
    where SupersededById ByIS NULL 
    UNION ALL 
    SELECT l.SupersededById, 
      l.LicenceId, 
      c.BaseId, 
      c.Level + 1 as Level 
    FROM Licence AS l 
      INNER JOIN c ON l.SupersededById = c.LicenceId 
) 
SELECT c1.LicenceId as OriginalLicence FROM c as c1 
WHERE c1.Level = (SELECT MAX(c2.Level) FROM c as c2 WHERE c2.BaseId = c1.BaseId) 

BTW : 소스 테이블에서 열을 추가하려면, 모든 SELECT에 추가하면됩니다.

+0

문제 해결을 보내 주셔서 감사합니다. 나는 서둘러 질의를하기 위해 노력하고있다. fyi : MaxRecursion 옵션없이 재귀 CTE를 게시 할 때마다 OP는 실제 데이터를 처리하는 기본 재귀 제한으로 실행됩니다. 그렇지 않으면 제안 할만한 가치가 있습니다. – HABO

+0

@HABO : 현실 세계에서 일어나는 100 가지 재판매가 실제로 이루어지기를 바랬지 만, Adsborough에게는 당신이해야 할 일이 무엇인지 알고 있습니다. :-) – TToni

+0

감사합니다 .TToni, 그러나 나는 생각합니다. 아직도 뭔가가 없습니다. 쿼리를 실행하면 모든 것이 레벨 1 결과로 표시됩니다 (일부 라이센스의 경우 최대 4 개까지 있음). 대신 마지막으로 참여하지 않아야합니까? INNER JOIN C ON l.upersededById = c.LicenceId – Adsborough