2009-06-19 2 views
2

다음 데이터를 필터링 할 수 있도록 쿼리를 구성하는 데 약간의 도움이 필요합니다.parentid가있는 테이블에서 자식 필터링

입니다
Id ParentId Visible 
===================== 
5 null  1 
6 5   1 

, 숨겨진 노드의 모든 아이들이 반환되지해야합니다

Table: MyTree 
Id ParentId Visible 
===================== 
1 null  0 
2 1   1 
3 2   1 
4 3   1 
5 null  1 
6 5   1 

나는 쿼리에서 다음과 같은 결과를 기대합니다. 더 중요한 것은 계층 구조의 깊이가 제한되지 않는다는 것입니다. 이제는 "2, 3 & 4를 visible = 0으로 설정하십시오."라고 대답하지 마십시오. 불가능하지 않은 이유는 ... 끔찍한 "레거시 시스템"을 수정하는 것과 같습니다.

내가 좋아하는 뭔가 생각 : 어떤 문법적인 실수

죄송

SELECT * 
FROM MyTree m1 
JOIN MyTree m2 ON m1.ParentId = m2.Id 
WHERE m1.Visible = 1 
AND (m1.ParentId IS NULL OR m2.Id IS NOT NULL) 

그러나 그것은 단지 오른쪽 첫 번째 레벨을 필터링 할 것인가? 당신이 도울 수 있기를 바랍니다.

편집 : 제목을 완료했습니다. 이 서버는 새로운 MSSQL 2008 서버의 브랜드이지만 데이터베이스는 2000 호환 모드로 실행됩니다. SQL Server 2005+에서

+1

어떤 버전의 SQL Server가 있습니까? –

+0

@ JohannesH - 당신이 성취하려는 것을 잘 모르겠다. –

+0

내가 생각하는 대답은 SQL Server 2005 이상 (재귀 CTE를 수행 할 수 있음) 또는 SQL Server 2000 - (수행 할 수 없음)에 따라 크게 달라집니다. – AakashM

답변

2

을 배웠지 만, 나는 논리를 생각 스탠드 빨리 눈에 보이지 않는 "하위 트리"를 따라 재귀를 중지 -

WITH visall(id, parentid, visible) AS 
    (SELECT id, parentid, visible 
    FROM mytree 
    WHERE parentid IS NULL 
     UNION ALL 
    SELECT m.id, m.parentid, m.visible & visall.visible AS visible 
    FROM visall 
    JOIN mytree m 
     ON m.parentid = visall.id 
    ) 
SELECT * 
FROM visall 
WHERE visall.visible = 1 

가능한 한 많이 WHERE에서 볼 수 검사를하는 것 같은 논리를 표현하는 아마 더 최적화 방법 : 원래의 질문에 대답 다르다. 즉 : - DB 엔진 '최적화로 성능 문제와 평소처럼

WITH visall(id, parentid, visible) AS 
    (SELECT id, parentid, visible 
    FROM mytree 
    WHERE parentid IS NULL AND visible = 1 
     UNION ALL 
    SELECT m.id, m.parentid, m.visible 
    FROM visall 
    JOIN mytree m 
     ON m.parentid = visall.id 
    WHERE m.visible = 1 
    ) 
SELECT * 
FROM visall 

, 실제 데이터에 대한 두 버전을 벤치마킹 자신있게 결정하는 것이 필요하다 (그것은 또한 그들이 실제로 어떻게 동일한 결과를 ;-) 생산 있는지 확인하는 데 도움이 이상한 일들을 이상한 이유로 때때로하는 경우도 있습니다.

+0

@Alex : 나는 네가 내가 한 것에 가장 가깝다고 생각한다. 그래서 당신의 대답을 받아 들였습니다. – JohannesH

+0

솔루션은 보이지 않는 노드를 가로 지른 다음 필터링합니다. 재귀 단계를 줄이기 위해 CTE에서 보이지 않는 노드를 필터링하는 것이 더 좋지 않습니까? – Quassnoi

+0

@JohannesH, 도와 줘서 기쁩니다. 예, @Quassnoi, 내 코드를 향상시킬 수 있다고 확신합니다 (재귀의 두 가지 지점에서 SELECT 대신 가시적 인 체크를 이동하십시오. shd help - 그런 식으로 최적화 된 코드를 추가하려면 편집하십시오). = 5 "는 묻는 사람이 염두에 두었던 것이 아니라 단지 하나의 예입니다. –

2

:

WITH q (id, parentid, visible) AS 
     (
     SELECT id, parentid, visible 
     FROM mytree 
     WHERE id = 5 
     UNION ALL 
     SELECT m.id, m.parentid, m.visible 
     FROM q 
     JOIN mytree m 
     ON  m.parentid = q.id 
     WHERE q.visible = 1 
     ) 
SELECT * 
FROM q 
-1

나는 당신이 필요로 생각하지 않는 단일 쿼리에서 가능하다. 이것은 코드에서 수행하는 것처럼 보이지만 여전히 DB에 여러 개의 쿼리가 필요합니다.

정말 SQL에서 할 필요가 있다면 최선의 방법은 커서를 사용하여 숨겨진 ID가있는 테이블을 작성하는 것입니다. 데이터가 자주 변경되지 않으면 '임시'테이블을 일종의 캐시로 유지할 수 있습니다.

편집 : 나는 (SQL 2005) 수정 및 새로운 무언가 오늘 : 내가 (SQL 서버 이후 2005 또는에서) 재귀 CTE를에 @ Quassnoi의 초점에 동의

+0

전 애플 리케이션의 코드에서해야하지만 전 불행히도 내가 소스가 없어 동의합니다. 레거시를 유지하는 것을 빨아 들인다. ;) – JohannesH

1

나는 Quassnoi가 질문자가 원하는 것에 가깝다고 생각하지만, 그렇지는 않습니다. 질문자가 찾고있는 것 (SQL Server 2005 이상) :

WITH q (id) AS 
     (
     SELECT id 
     FROM mytree 
     WHERE parentid is null and visible=1 
     UNION ALL 
     SELECT m.id 
     FROM q 
     JOIN mytree m 
     ON  m.parentid = q.id 
     WHERE q.visible = 1 
     ) 
SELECT * 
FROM q 

일반 테이블 식은 이러한 종류의 작업에 적합합니다.