2017-03-23 29 views
9

2番目のテーブルに結合するときに複数のテーブルを結合し、3番目のテーブルに句を持つことを試みています。私はどこで句を試してみましたが、2番目のテーブルの列を無効にしたいときは、結果全体に適用されます。他のテーブルの条件付きテーブルへの左結合テーブル

例を置くと、より明確になります。 私は4つのテーブルを有する:サンプルデータがあろう

表CおよびDに、テーブルAを結合

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); 

テーブルBを:

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); 

直接左ジョイン:

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; 

は、データを返します。

╔══════╦══════╦══════╦══════╗ 
║ 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 ║ 
╚══════╩══════╩══════╩══════╝ 

私がしようとしているのは、CテーブルとDテーブルのデータでBテーブルをフィルタリングすることです。私は単に要求にWHERE条件を追加する場合 :それはロジックだ

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

を私は望んでいないものを:

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); 

それを返します。私が欲しいのです:

A.ID = 2で行を保持しますが、私は入社 ON句で条件を入れてみましたCとD

からの一致条件とBに値が見つからない

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

CとDのテーブルがありますが、それは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 ║ 
╚══════╩══════╩══════╩══════╝ 

私は今トリックをするアイデアがありません。あなたがする必要がどのような

+2

あなたの条件をどこからジョイントパートに移動してみることができますか? – Veljko89

+0

I. WHEREからONへ。 – jarlh

+0

@jarlhそれは私が務めているものです、 – Veljko89

答えて

4

値がcまたはd条件の列のいずれかに存在する場合aテーブルにそれをバック左外部結合が最初cdテーブルにbテーブルから参加しており、その後、外。そのような(!私の編集した出力の問題をスポッティングためのアレックス・プールのおかげで)

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      


ETA:

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; 

これは、のように書くこともできました

これは単純ですが、意図を解読するのが難しくなる可能性があります(したがって将来的には維持するのが難しい)。私はこれが有効な構文であるとは知らなかったのでここに追加しました。

+0

この解決策は質問に答えているようですが、選択なしで「サブクエリ」というこの構文は何ですか? – Pilou

+0

[ドキュメント](http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_10002.htm#i2080416)のように、ジョインのかっこはデフォルトの結合優先順位を上書きします。 – Boneist

0

私は本当に間違っているとして以前のものを削除したので、私は別の答えを追加しています。私はこれが正しいロジックだと思う:

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

これは正しいテスト結果を返します。

興味深い問題です。考え方は、かっこを使用してABの間の比較を「遅延」させることです。これにより、条件がCまたはDに一致するかどうかを判別することもできます。

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; 

私にはわからないソリューションは、より良いテーブルと大きなB、C上の他の句を持つ実行しますwhiwh:

0

は、実際に私はON句のサブクエリでそれを行うための別の方法を見つけましたおよびDテーブル。

関連する問題