

現在oracleで使用しているsql文をsqlserverで使えるように書式を変更しています。  
そこで、以下のようなsql文について、書き換えを試みているのですが、  
select結果が同じになりません。

(+)を利用したsql文の挙動が理解できておらず、  
申し訳ありませんがご教示いただきたいです。

**書き換え元--oracle--**

[code]

    SELECT 
    A.id,
    A.name,
    B.address,
    C.tel1,
    C.tel2,
    D.sex
    FROM TBL_A A,TBL_B B,TBL_C C,TBL_D D
    WHERE 
    A.id = '000001',
    A.id = D.id,
    A.id = B.id(+),
    A.id = C.id(+),
    B.address = C.address(+),
    B.customer_name = D.customer_name(+)
    
[/code]

上記のように内部結合して、  
複数テーブルで(+)を用いた外部結合をするsqlを  
left joinを使用したsqlに書き換えたいのですが、  
select結果が異なってしまいます。

どのように書き換えるのが正解なのか教えていただきたいです。

以下のような単純な書き換えは理解できるのですが、  
複数(内部結合と外部結合の組み合わせ)が全く分からず。。

(+)での外部結合

[code]

    SELECT 
    A.id,
    B.address
    FROM TBL_A A,TBL_B B
    A.id = B.id(+)
    
[/code]

left join 書き換え

[code]

    SELECT 
    A.id,
    B.address
    FROM TBL_A A 
    LEFT JOIN TBL_B B
    ON A.id = B.id
    
[/code]

以上、お分かりになる方がいらっしゃいましたらご教示ください。  
また、不足している・分かりにくい点がありましたら  
ご指摘ください。修正させていただきます。

宜しくお願い致します。


CC BY-SA 4.0
2019-07-28T00:09:27.220
56948
2019-07-29T07:40:57.563
2019-07-28T02:54:14.310
13251
13251
question
sql sql-server oracle
oracleの外部結合表現(+)からleft joinへの書き換えがうまくいきません


基本的な1対1の外部結合を理解されておられるようですので、1対nの外部結合は **外部テーブル(今回のテーブルAに該当)に複数の`left
join`できる**ことを応用すれば解決できるはずです。

第三者への有益な情報を目指して簡単なところから記載します。  
記載されているSQLは質問と若干違います。MySQLのテーブル構成および実行結果は[SQL
Fiddle](http://sqlfiddle.com/#!9/c37421/8)のリンク先を参照してください。

なお質問にある変換前のOracleのSQLは多重外部結合なので`Oracle 11g`以前では下記の **エラーが発生** して動きません。

> ORA-01417: 表が少なくとも1つの他の表に外部結合されている可能性があります。

SQL Fiddleは11gが対象で例示できないため、冗長ですがwith句でテーブルを代用しています。  
もちろん実行は12c以降で行ってください。

### A left outer join on B

まずはテーブルAとBを結合します。(既に質問で例示されているSQLと類似しています)

[code]

    -- 2 tables in Oracle
    with  A as
         (select 1 id, 'name1' name from dual union all
          select 2 id, 'name2' name from dual union all
          select 3 id, 'name3' name from dual union all
          select 4 id, 'name4' name from dual union all
          select 5 id, 'name5' name from dual)
         ,B as
         (select 1 id, 'customer1' customer_name, 'address1' address from dual union all
          select 2 id, 'customer2' customer_name, 'address2' address from dual union all
          select 4 id, 'customer4' customer_name, 'address4' address from dual)
    select   A.id, name,
             B.address
    from     A, B
    where    A.id = B.id(+)
    order by A.id
    
[/code]

[code]

    -- 2 tables in SQL Server
    select   A.id, name,
             B.address
    from     A
             left join B on A.id = B.id
    order by A.id
    
[/code]

### A on B, C

次に複数テーブルの外部結合です。  
テーブルAとBに加えてテーブルAとCも外部結合します。  
`left join`を複数行積むことで、1つの外部テーブルに複数のテーブルを連結できます。  
まだテーブルBとCは結合していません。

[code]

    -- A on B, C in Oracle
    with  A as
         (select 1 id, 'name1' name from dual union all
          select 2 id, 'name2' name from dual union all
          select 3 id, 'name3' name from dual union all
          select 4 id, 'name4' name from dual union all
          select 5 id, 'name5' name from dual)
         ,B as
         (select 1 id, 'customer1' customer_name, 'address1' address from dual union all
          select 2 id, 'customer2' customer_name, 'address2' address from dual union all
          select 4 id, 'customer4' customer_name, 'address4' address from dual)
         ,C as
         (select 1 id, 'address1' address, 'tel1' tel from dual union all
          select 3 id, 'address3' address, 'tel3' tel from dual union all
          select 5 id, 'address5' address, 'tel5' tel from dual)select   A.id, name,
             B.address,
             C.tel
    from     A, B, C
    where    A.id = B.id(+)
    and      A.id = C.id(+)
    order by A.id
    
[/code]

[code]

    -- A on B, C in SQL Server
    select   A.id, name,
             B.address,
             C.tel
    from     A
             left join B on A.id = B.id
             left join C on A.id = C.id
    order by A.id
    
[/code]

### A on B, C and B on C

そろそろ厄介なところで、Oracleでも12cでようやく(+)が対応したSQLです。  
とは言えANSI準拠の外部結合ならば、AとCの結合条件にandを加えてBとCを結合するだけです。

[code]

    -- A on B, C and B on C in Oracle 12c-
    with  A as
         (select 1 id, 'name1' name from dual union all
          select 2 id, 'name2' name from dual union all
          select 3 id, 'name3' name from dual union all
          select 4 id, 'name4' name from dual union all
          select 5 id, 'name5' name from dual)
         ,B as
         (select 1 id, 'customer1' customer_name, 'address1' address from dual union all
          select 2 id, 'customer2' customer_name, 'address2' address from dual union all
          select 4 id, 'customer4' customer_name, 'address4' address from dual)
         ,C as
         (select 1 id, 'address1' address, 'tel1' tel from dual union all
          select 3 id, 'address3' address, 'tel3' tel from dual union all
          select 5 id, 'address5' address, 'tel5' tel from dual)
    select   A.id, name,
             B.address,
             C.tel
    from     A, B, C
    where    A.id = B.id(+)
    and      A.id = C.id(+)
    and      B.address = C.address(+)
    order by A.id
    
[/code]

[code]

    -- A on B, C and B on C in SQL Server
    select   A.id, name,
             B.address,
             C.tel
    from     A
             left join B  on A.id = B.id
             left join C  on A.id = C.id
                         and B.address = C.address
    order by A.id
    
[/code]

### A, D and A on B on C and A on C and D on B

最後にこれまでの内容を踏まえてテーブルDを結合します。  
AとDをwhere句で結合するとBとDのleft joinでエラーになるので、inner joinでAとDを先に等価結合しておきます。

質問のSQLとは異なりますが、B on DでBを外部結合すると、Bにないレコードが消えて外部結合の意味が薄れるので、D on BでDを外部結合しています。  
また外部結合であることを示すため、Dのcustomer_nameとsexにnullが入っているレコードがあります。

[code]

    -- A, D and A on B on C and A on C and D on B in Oracle 12c-
    with  A as
         (select 1 id, 'name1' name from dual union all
          select 2 id, 'name2' name from dual union all
          select 3 id, 'name3' name from dual union all
          select 4 id, 'name4' name from dual union all
          select 5 id, 'name5' name from dual)
         ,B as
         (select 1 id, 'customer1' customer_name, 'address1' address from dual union all
          select 3 id, 'customer3' customer_name, 'address3' address from dual union all
          select 4 id, 'customer4' customer_name, 'address4' address from dual)
         ,C as
         (select 1 id, 'address1' address, 'tel1' tel from dual union all
          select 3 id, 'address3' address, 'tel3' tel from dual union all
          select 5 id, 'address5' address, 'tel5' tel from dual)
         ,D as
         (select 1 id, 'customer1' customer_name, '1' sex from dual union all
          select 2 id, 'customer2' customer_name, '2' sex from dual union all
          select 3 id, 'customer3' customer_name, '3' sex from dual union all
          select 4 id, 'customer4' customer_name, '4' sex from dual union all
          select 5 id, 'customer5' customer_name, '5' sex from dual)
    select   A.id, name,
             B.address,
             C.tel,
             D.sex
    from     A, B, C, D
    where    A.id = D.id
    and      A.id = B.id(+)
    and      A.id = C.id(+)
    and      B.address = C.address(+)
    and      B.customer_name = D.customer_name(+)
    order by A.id
    
[/code]

[code]

    -- A, D and A on B on C and A on C and D on B in SQL Server
    select   A.id, name,
             B.address,
             C.tel,
             D.sex
    from     A
             inner join D on A.id = D.id
             left join B  on A.id = B.id
                         and D.customer_name = B.customer_name  -- D on B
             left join C  on A.id = C.id
                         and B.address = C.address
    order by A.id
    
[/code]


CC BY-SA 4.0
2019-07-29T07:40:57.563
57006
2019-07-29T07:40:57.563
9820
56948
answer