2017-03-23 8 views
9

Próbuję pozostawić dołączyć wiele tabel i mając klauzulę na trzeciej tabeli przy dołączaniu do drugiej. Próbowałem z klauzulami where, ale dotyczy to całego wyniku, gdy chcę tylko unieważnić kolumny z drugiego stołu.Lewe sprzężenie na stole z warunkiem na innych tabelach

Połóżmy przykład, będzie to bardziej przejrzyste. mam 4 tabel:

CREATE TABLE A (ID INTEGER PRIMARY KEY); 
CREATE TABLE B (ID INTEGER PRIMARY KEY, A_ID INTEGER, C_ID INTEGER, D_ID INTEGER); 
CREATE TABLE C (ID INTEGER PRIMARY KEY, CONDITIONS INTEGER); 
CREATE TABLE D (ID INTEGER PRIMARY KEY, CONDITIONS INTEGER); 

Tabela B Połączenie tabeli A w tabelach C i D

są przykładowe będą:

INSERT INTO A VALUES (1); 
INSERT INTO A VALUES (2); 
INSERT INTO A VALUES (3); 

INSERT INTO C VALUES (1, 1); 
INSERT INTO C VALUES (2, 1); 
INSERT INTO C VALUES (3, 0); 

INSERT INTO D VALUES (1, 0); 
INSERT INTO D VALUES (2, 0); 

INSERT INTO B VALUES (1, 1, 1, NULL); 
INSERT INTO B VALUES (2, 1, 2, NULL); 
INSERT INTO B VALUES (3, 1, 3, NULL); 
INSERT INTO B VALUES (4, 2, NULL, 1); 
INSERT INTO B VALUES (5, 2, NULL, 2); 

Bezpośrednie lewej dołączenie:

SELECT A.ID, B.ID, C.ID, D.ID 
FROM A 
LEFT JOIN B ON B.A_ID = A.ID 
LEFT JOIN C ON B.C_ID = C.ID 
LEFT JOIN D ON B.D_ID = D.ID; 

zwraca dane:

╔══════╦══════╦══════╦══════╗ 
║ A.id ║ B.id ║ C.id ║ D.id ║ 
╠══════╬══════╬══════╬══════╣ 
║ 1 ║ 1 ║ 1 ║ null ║ 
║ 1 ║ 2 ║ 2 ║ null ║ 
║ 1 ║ 3 ║ 3 ║ null ║ 
║ 2 ║ 4 ║ null ║ 1 ║ 
║ 2 ║ 5 ║ null ║ 2 ║ 
║ 3 ║ null ║ null ║ null ║ 
╚══════╩══════╩══════╩══════╝ 

Co próbuję zrobić, to filtrować tabelę B danymi z tabel C i D. Gdybym po prostu dodać warunek WHERE na żądanie:

SELECT A.ID, B.ID, C.ID, D.ID 
FROM A 
LEFT JOIN B ON B.A_ID = A.ID 
LEFT JOIN C ON B.C_ID = C.ID 
LEFT JOIN D ON B.D_ID = D.ID 
WHERE (C.ID IS NULL OR C.CONDITIONS = 1) 
AND (D.ID IS NULL OR D.CONDITIONS = 1); 

Zwraca:

╔══════╦══════╦══════╦══════╗ 
║ A.id ║ B.id ║ C.id ║ D.id ║ 
╠══════╬══════╬══════╬══════╣ 
║ 1 ║ 1 ║ 1 ║ null ║ 
║ 1 ║ 2 ║ 2 ║ null ║ 
║ 3 ║ null ║ null ║ null ║ 
╚══════╩══════╩══════╩══════╝ 

którym jest logiczny, ale nie to, co chcę. Co chcę jest:

╔══════╦══════╦══════╦══════╗ 
║ A.id ║ B.id ║ C.id ║ D.id ║ 
╠══════╬══════╬══════╬══════╣ 
║ 1 ║ 1 ║ 1 ║ null ║ 
║ 1 ║ 2 ║ 2 ║ null ║ 
║ 2 ║ null ║ null ║ null ║ 
║ 3 ║ null ║ null ║ null ║ 
╚══════╩══════╩══════╩══════╝ 

który utrzymuje wiersz z A.ID = 2 ale znajdzie żadnej wartości w B ze stanu dopasowania od C i D.

próbowałem umieścić warunków w klauzuli ON przystąpienie do Tabele C i D, ale przechowują dane z B:

╔══════╦══════╦══════╦══════╗ 
║ A.id ║ B.id ║ C.id ║ D.id ║ 
╠══════╬══════╬══════╬══════╣ 
║ 1 ║ 1 ║ 1 ║ null ║ 
║ 1 ║ 2 ║ 2 ║ null ║ 
║ 1 ║ 3 ║ null ║ null ║ 
║ 2 ║ 4 ║ null ║ null ║ 
║ 2 ║ 5 ║ null ║ null ║ 
║ 3 ║ null ║ null ║ null ║ 
╚══════╩══════╩══════╩══════╝ 

Brakuje mi pomysłów na zrobienie tego.

+2

Czy możesz spróbować przenieść swoje warunki z miejsca do części łączenia? – Veljko89

+0

tj. od WHERE do ON. – jarlh

+0

@jarlh To jest to, co mówię, dziękuję – Veljko89

Odpowiedz

4

Co trzeba zrobić, to lewa zewnętrzna łączy ze stołu b do c i d stołach, a potem, że zewnętrzna dołączyć do stołu a czy wartość istnieje ani w c lub d warunki kolumn. Tak:

SELECT a.id a_id, b2.b_id, b2.c_id, b2.d_id 
FROM a 
     LEFT OUTER JOIN (SELECT b.id b_id, 
           b.a_id, 
           c.id c_id, 
           d.id d_id 
         FROM b 
           LEFT OUTER JOIN c ON b.c_id = c.id AND c.conditions = 1 
           LEFT OUTER JOIN d ON b.d_id = d.id AND d.conditions = 1) b2 
     ON a.id = b2.a_id AND COALESCE(b2.c_id, b2.d_id) IS NOT NULL 
ORDER BY a.id, b2.b_id, b2.c_id, b2.d_id; 

     A_ID  B_ID  C_ID  D_ID 
---------- ---------- ---------- ---------- 
     1   1   1 
     1   2   2 
     2      
     3      

(! Dzięki Alex Poole na plamienie problemy z moją redakcją wyjściu)


ETA:

To może również być zapisany jako:

SELECT a.id a_id, b.id b_id, c.id c_id, d.id d_id 
FROM a 
     LEFT OUTER JOIN (b 
         LEFT OUTER JOIN c ON b.c_id = c.id AND c.conditions = 1 
         LEFT OUTER JOIN d ON b.d_id = d.id AND d.conditions = 1) 
     ON a.id = b.a_id AND COALESCE(c.id, d.id) IS NOT NULL 
ORDER BY a.id, b.id, b.c_id, b.d_id; 

co jest prostsze, ale potencjalnie trudniejsze do rozszyfrowania intencji (a zatem trudniejsze do utrzymania w przyszłości). Dodałem go tutaj, ponieważ nie miałem pojęcia, że ​​to jest poprawna składnia, i możesz poczuć, że działa lepiej dla ciebie.

+0

To rozwiązanie wydaje się odpowiadać na pytanie, ale jaka jest ta składnia z "podzapytaniem" bez wyboru? – Pilou

+0

Nawiasy w połączeniach mają zastąpić domyślne pierwszeństwo łączenia - zgodnie z [dokumentacją] (http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_10002.htm#i2080416). – Boneist

0

Dodaję kolejną odpowiedź, ponieważ naprawdę usunąłem poprzednią jako niepoprawną.Myślę, że jest to poprawna logika:

Powoduje to, że zwracam prawidłowe wyniki, gdy testuję.

To interesujący problem. Pomysł polega na użyciu nawiasów, aby "opóźnić" porównanie między A i B. Dzięki temu warunek może również określać, czy pasuje on do C lub D.

0

Właściwie znalazłem inny sposób to zrobić z podzapytania w klauzuli ON:

SELECT A.ID, B.ID, C.ID, D.ID 
FROM A 
LEFT JOIN B ON B.A_ID = A.ID 
    AND (B.C_ID IS NULL OR B.ID IN (SELECT B.ID FROM B JOIN C ON C.ID = B.C_ID AND C.CONDITIONS = 1) 
    AND (B.D_ID IS NULL OR B.ID IN (SELECT B.ID FROM B JOIN D ON D.ID = B.D_ID AND D.CONDITIONS = 1) 
LEFT JOIN C ON B.C_ID = C.ID 
LEFT JOIN D ON B.D_ID = D.ID; 

nie wiem whiwh rozwiązanie będzie działać lepiej posiadające inną klauzulę na stole i duże B, C i D tabel.

Powiązane problemy