2011-11-20 14 views
9

Załóżmy, że mam tabelę z relacjami rodzic-dziecko.Znajdowanie wszystkich dzieci dla wielu rodziców w pojedynczym zapytaniu SQL

 
parent child 
1  4 
1  5 
2  6 
3  7 
4  8 
6  9 
7  10 
8  11 

Teraz mam kwerendę, która zwraca listę osób (np. 1 i 2) i chcę, aby znaleźć wszystkie swoje dzieci, wnuki itd (w tym przypadku: 4, 5, 6, 8, 9, 11).

Wiem, że mogę używać typowych wyrażeń tabel do rekursywnego wyszukiwania, ale zastanawiałem się, czy mogę utworzyć instrukcję SQL, aby znaleźć wszystkich potomków jednocześnie, bez konieczności wykonywania iteracji przez zestaw wejściowy.

Edytuj: Przepraszam za brak jasności. Szukam czegoś podobnego:

 
SELECT {Hierarchical relation} from table where parent in (1,2) 

co powinno skutkować w jednej kolumnie wyjścia z wierszami dla 4, 5, 6, 8, 9, 11.

ja nie jestem już zainteresowany w związek w wynikach, tylko pełny zestaw członków rodziny dla wielu rodzin.

+0

Czy dane wyjściowe muszą wskazywać na ich związek (dziecko, wnuczek itp.) Lub czy są one po prostu zstępowane? – UnhandledExcepSean

+0

Czy możesz podać nam próbkę oczekiwanego wyniku w formacie tabeli/kolumny-kolumny, tak jak ilustrujesz tabelę relacjami rodzic-dziecko? – Nonym

+0

Nonym, dodałem oczekiwane wyjście do pytania. – MvdD

Odpowiedz

16

Tu jest

---- PlainTable ---- 
parent idElement (child) 
Null 1 
1  4 
1  5 
2  6 
3  7 
4  8 
6  9 
7  10 
8  11 

WITH tableR (parent, idElement) 
AS 
(
-- Anchor member definition 
    SELECT e.parent, e.idElement 
    FROM PlainTable AS e 
    WHERE parent in (1,2) 
    UNION ALL 
-- Recursive member definition 
    SELECT e.parent, e.idElement 
    FROM PlainTable AS e 
    INNER JOIN tableR AS d 
     ON e.parent = d.idElement 
) 
-- Statement that executes the CTE 
SELECT idElement 
FROM tableR --inner join to plain table by id if needed 
+0

Ten CTE przeszukuje hierarchiczną relację, tak jak zamierzałem, ale tylko dla pojedynczego wejścia. Zobacz moją edycję w pytaniu. – MvdD

+0

Pierwsze zapytanie CTE szuka węzłów głównych, zakładam, że węzły główne mają NULL jako nadrzędne. Zmień to zapytanie na inne kryteria. – danihp

+0

Wypróbuj zapytanie w SQL Management Studio. Znajduje wszystkie potomki dla rodzica IS NULL, które są (1, 4, 5, 8 i 11), a następnie zwraca tylko 1 z tego zestawu wyników. Jak wspomniałem w powyższym pytaniu, wyjście powinno być kolumną z (1, 2, 4, 5, 6, 8, 9, 11), które są potomkami dla obydwu rodziców 1 i 2. – MvdD

0

SQL Server 2008 ma wbudowane funkcje, które ułatwiają dane hierarchiczne: http://msdn.microsoft.com/en-us/magazine/cc794278.aspx

wiem, że mogę użyć typowych wyrażeń tabeli szukać rekurencyjnie, ale zastanawiał się, czy mogę utworzyć instrukcję SQL, aby znaleźć wszystkie potomków pod raz bez konieczności iteracji nad zestawem wejściowym.

Nie jestem pewien, co przez to rozumiesz. Większość (może wszystkie?) CTE można zrealizować za pomocą podkwerend, ale użycie podkwerendy nie byłoby szybsze. Kiedy mówisz, że nie chcesz "iterować" nad zestawem wejściowym, brzmi to tak, jakbyś mówił o użyciu kursorów i oczywiście możesz to zrobić jako operację opartą na zestawie (używając CTE lub podkwerend), ale nie ma sposób wokół rekurencji.

Edycja: Przepraszam, nie myślę wprost ... oczywiście nie można wykonywać rekursji z normalnymi podzapytaniami, ale punkt wciąż oznacza, że ​​nawet gdybyś mógł, nie byłby szybszy. Jeśli chcesz zobaczyć strategie wykonywania rekurencji bez CTE, spróbuj wyszukać coś takiego jak "rekursja sql 2000", ponieważ CTE nie były wtedy w pobliżu. Oto kilka przykładów: http://www.mssqltips.com/sqlservertip/938/recursive-queries-with-sql-server-2000/. Oczywiście odpowiedź na twoje pytanie pozostaje jednak taka sama.

0

Czekając na zaktualizowanej postu:

SELECT DISTINCT 
    p.parent AS parent 
, c.child AS child 
, IFNULL(g.child, 'NONE') AS grandchild_of_parent 
FROM parent_child as p 
LEFT JOIN parent_child AS c ON p.parent = c.parent 
LEFT JOIN parent_child AS g ON c.child = g.parent; 

Wyniki będzie wyglądać następująco:

parent child grandchild_of_parent 
1  4  8 
1  5  NONE 
2  6  9 
3  7  10 
4  8  11 
6  9  NONE 
7  10  NONE 
8  11  NONE 

Taki prostolinijny, ale zapewne-trudniejszy w utrzymaniu rodzaj kodu, ale ponieważ nie jestem zaznajomiony z wbudowanymi funkcjami programu SQL Server 2008 do obsługi tego typu żądania, po prostu rzucę długie ujęcie ...

EDYTOWANIE:

Tak więc można zobaczyć wyniki dla siebie podczas studiowania common table expressions i/lub może pivots ... to będzie uzyskać wyniki, ale tylko do wielkich wnuków 1 i 2.

-- A. Parents 1 and 2 
SELECT DISTINCT p.parent FROM parent_child AS p 
WHERE p.parent IN (1,2) 
UNION 
-- B : Children of A 
SELECT DISTINCT p.child FROM parent_child AS p 
WHERE p.parent IN (1,2) 
UNION 
-- C : Children of B, Grandchildren of A 
SELECT DISTINCT p.child FROM parent_child AS p 
WHERE p.parent IN (
    SELECT DISTINCT p.child FROM parent_child AS p 
    WHERE p.parent IN (1,2) 
) 
UNION 
-- D : Children of C, Great-Grandchildren of A 
SELECT DISTINCT p.child FROM parent_child AS p 
WHERE p.parent IN (
    SELECT DISTINCT p.child FROM parent_child AS p 
    WHERE p.parent IN (
    SELECT DISTINCT p.child FROM parent_child AS p 
    WHERE p.parent IN (1,2) 
) 
) 

Znowu zdecydowanie sugeruję, abyś przestudiował to, co inni publikowali .. i zajrzyj do podanych linków. Zapytanie, które ci podałem, nie potrwa długo-> będzie absolutnie FAIL, kiedy już będziecie pra-pra-wnuki.

+0

Poszukuję pojedynczej kolumny z wszystkimi powiązanymi identyfikatorami. – MvdD

+0

BTW, IFNULL powinno być ISNULL w kwerendzie powyżej dla SQL Server. – MvdD

0

Ok, rozwiązanie danihp za nie umieścić mnie na właściwe tory. Jest to rozwiązanie wymyśliłem:

DECLARE @Input TABLE (
    id int 
) 

INSERT INTO @Input VALUES (1),(2) 

;WITH Relations (parent, child) 
AS 
(
    SELECT e.parent, e.child 
     FROM RelationTable AS e 
     WHERE parent in (SELECT * FROM @Input) 
    UNION ALL 
     SELECT e.parent, e.child 
     FROM RelationTable AS e 
     INNER JOIN Relations AS d 
      ON e.parent = d.child 
) 
SELECT child 
FROM Relations 

Skutkuje listę identyfikatorów podrzędnych (z wyłączeniem identyfikatory nadrzędne 2 jak powiedziałem wcześniej w pytaniu): 4,5,6,8,9, 11

+0

oh! Przepraszam! Mój błąd: "WHERE idElement in (1,2)" może pojawić się w pierwszym zapytaniu, nie w ostatnim! Naprawię to. – danihp

0
---- PlainTable ---- 
parent idElement (child_id) 
    Null 1 
    1  4 
    1  5 
    2  6 
    3  7 
    4  8 
    6  9 
    7  10 
    8  11 

**Table value function to get Child ids at 4(any) Level of parent in the same table:-** 

    FUNCTION fc_get_Child_IDs(Parent) 
    DECLARE @tbl TABLE (ID int) 
    DECLARE @level int=4 
    DECLARE @i int=1 
    insert into @tbl values (Parent) 
    while @i < @level 
    BEGIN 

    INSERT into @tbl 
    select child_id from PlainTable where Parent in (select ID from @tbl) and child_id not in (select ID from @tbl) 
    set @i = @i + 1 
    END 
Powiązane problemy