2014-02-27 6 views
1

테이블이 Element (id int, type nvarchar)입니다. 각 요소 에 하나 이상의 부모가 있으며, 유형에 따라 일부 개의 관계가 정의됩니다. 부모는 자신의 집합을 가질 수 있습니다 규칙에 의해 정의 된 자신의 유형입니다.어떻게 CTE를 함수와 결합하여 재귀 적으로 사용할 수 있습니까?

내가하고 싶은 일은 다른 요소의 조상 (부모, 부모의 부모, ...) 인 모든 Element 레코드를 쿼리하는 것입니다.

나는 idtype이 주어진 요소를 위해 부모 목록을 반환하는 함수를 정의했습니다.

CREATE FUNCTION [dbo].[GetParentElementIds] ( 
    @ElementId int, 
    @ElementType nvarchar(50) 
) 
RETURNS @ParentElementIds TABLE (id int primary key not null, type nvarchar(50) not null) 
AS 
BEGIN 
    IF @ElementType = 'channel' BEGIN 
     DECLARE @PortId int 

     -- Some logic to map the @ElementId to a related @PortId 

     INSERT INTO @ParentElementIds VALUES (@PortId, 'port') 
    END ELSE IF @ElementType = 'port' BEGIN 
     DECLARE @CardId int 

     -- Some logic to map the @ElementId to a related @CardId 

     INSERT INTO @ParentElementIds VALUES (@CardId, 'card') 
    END 

    RETURN 
END 

... 그 작품은 그 자체입니다. 다음으로 결과 집합에 GetParentElementIds()을 반복적으로 호출하여 조상 목록을 가져 오는 재귀 적 CTE를 만들고 싶습니다. 불행하게도, 내 마스터 플랜가 주춤하기 시작 곳이다, 나는 정확한 쿼리 구문에 너무 확실하지 않다 :

WITH all_ancestor_elements (element_id, type) 
AS (
    SELECT id AS element_id, type FROM Element WHERE id IN (SELECT id FROM dbo.GetParentElementIds(5, 'channel')) 
UNION ALL 
    SELECT dbo.GetParentElementIds(e.id, e.type) FROM Element e WHERE e.id IN (SELECT element_id FROM all_ancestor_elements) 
) 

SELECT * FROM all_ancestor_elements; 

내가 오류는 다음과 같습니다

메시지 465, 수준 16, 상태 1, 줄 5 하위 쿼리에 순환 참조가 허용되지 않습니다.

도움이 필요합니다. 나는 현재의 접근 방식에 강요 당하지 않으며, 더 좋은 것들을 기꺼이 환영 할 것이다. 이것은 단순히 내가 가장 좋아하는 것으로 선택한 길입니다.

SELECT g.id, g.type 
FROM Element e 
     CROSS APPLY dbo.GetParentElementIds(e.id, e.type) g 

내가 아니다 :

SELECT dbo.GetParentElementIds(e.id, e.type) FROM Element e 

당신은 같은 것을 사용해야합니다 : 당신이 여기에 테이블 반환 함수를 호출하는 방법을

감사합니다, 매트

답변

1

이 문제는 정확한 논리를 100 % 확신 할 수는 있지만 최종 쿼리가 다음과 같이 끝날 것이라고 추측 할 수 있습니다.

WITH all_ancestor_elements (element_id, type) 
AS (
    SELECT id AS element_id, type 
    FROM Element 
    WHERE id IN (SELECT id FROM dbo.GetParentElementIds(5, 'channel')) 
    UNION ALL 
    SELECT g.id, g.type 
    FROM all_ancestor_elements e 
      CROSS APPLY dbo.GetDirectAffectorElementIds(e.element_id, e.type) g 
) 
SELECT * 
FROM all_ancestor_elements; 
+0

Humm ... 불행히도 나는 Element 테이블에서 1 백만 행을 넘었습니다. 쿼리의 개별 부분을 수동으로 구성하면 CTE 앵커가 1ms 미만에서 실행되어 단일 행을 반환합니다. 재귀 적 케이스에서 그 결과를 실행하면 또 하나의 결과가 반환되고, 재귀 적 케이스에서 실행하면 결과가 반환되지 않으므로 ... 수행해야합니다. 이 3 가지 쿼리 각각은 <1ms가 소요되지만 CTE를 ur, CTE로 실행하면 CTE는 5 분 이상 실행됩니다. 작성한 쿼리를 최적화하는 방법은 무엇입니까? – Isaac

+0

샘플 데이터가 없어도 http://sqlfiddle.com/에 샘플 데이터를 게시 할 수 있습니까? – GarethD

+0

필자는 기꺼이 한 번 생각해 보겠다.하지만 불행하게도 필자가 내 기능에서 생략 한 "일부 논리"는 매우 복잡하며 데이터베이스에 여러 개의 다른 테이블을 사용한다. SQLFiddle에 놓는 것은 쉽지 않을 것입니다! 그러나, 나는' \t \t \t \t CROSS이 dbo.GetDirectAffectorElementIds (e.element_id, E를 적용 all_ancestor_elements 전자로부터 \t \t을 g.type, g.id SELECT에 재귀 사건을 변경했습니다.type) g'이고 예상대로 작동하는 것으로 보이며 실행하려면 <1ms가 걸립니다. – Isaac