Oracleでは外部結合の(+)が非推奨なので勉強してみた

プロダクトコードで使われているSQLに外部結合で  **(+)** がよくつかわれているが、11g以降非推奨だと聞いたので、個人的には保守以外であまり使わないが、必要に駆られて勉強してみた。


**SQL関連の書籍でおすすめの一冊はこちら！！！**
<a href="https://hb.afl.rakuten.co.jp/ichiba/0fe6b456.5ebf4c8d.0fe6b457.c2862225/?pc=https%3A%2F%2Fproduct.rakuten.co.jp%2Fproduct%2F-%2F155d07bf69f979c71f1b91bcb99d241a%2F&link_type=pict&ut=eyJwYWdlIjoiaXRlbSIsInR5cGUiOiJwaWN0Iiwic2l6ZSI6IjQwMHg0MDAiLCJuYW0iOjEsIm5hbXAiOiJyaWdodCIsImNvbSI6MSwiY29tcCI6ImRvd24iLCJwcmljZSI6MCwiYm9yIjoxLCJjb2wiOjEsImJidG4iOjEsInByb2QiOjEsImFtcCI6ZmFsc2V9" target="_blank" rel="nofollow sponsored noopener" style="word-wrap:break-word;"  ><img src="https://hbb.afl.rakuten.co.jp/hgb/1e8530d6.19a113c9.1e8530d7.fe2e9cd6/?me_id=1213310&item_id=16284663&pc=https%3A%2F%2Fthumbnail.image.rakuten.co.jp%2F%400_mall%2Fbook%2Fcabinet%2F5894%2F9784873115894.jpg%3F_ex%3D400x400&s=400x400&t=pict" border="0" style="margin:2px" alt="" title=""></a>
<a target="_blank" href="https://www.amazon.co.jp/gp/product/4873115892/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4873115892&linkCode=as2&tag=soepy-22&linkId=99ca2ee1ac7230cbb3583f29b9e561e1">SQLアンチパターン／BillKarwin／和田卓人／和田省二</a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=soepy-22&l=am2&o=9&a=4873115892" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

# 外部結合とは
## 外部結合とは


**外部結合とは2つのテーブルでそれぞれ結合の対象となるカラムを指定し、それぞれのカラムに同じ値が格納されているデータを結合して取得するものです。内部結合の場合は、一致しないデータは取得しませんでしたが、外部結合の場合は一致しない場合もデータとして取得します。**
引用元 : [外部結合とは](https://www.dbonline.jp/sqlite/join/index2.html#:~:text=%E5%A4%96%E9%83%A8%E7%B5%90%E5%90%88%E3%81%A8%E3%81%AF2,%E3%83%87%E3%83%BC%E3%82%BF%E3%81%A8%E3%81%97%E3%81%A6%E5%8F%96%E5%BE%97%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)

つまりよくある以下のようなSQL

```sql

select 
  h.hoge1,h.hoge2,h.hoge3,f.fuga1,f.fuga2,f.fuga3 
from 
  HOGE h,FUGA f 
where 
  h.hoge1 = f.fuga1
```

これは **内部結合** であり、 **h.hoge1 = f.fuga1** が一致しないもの、つまり一方にしか存在しない場合は取得できないという事になる。
他方、非推奨とされる **(+)** を使った **外部結合** でSQLを書くと以下のように書ける.

#### 右外部結合

```sql
select 
  h.hoge1,h.hoge2,h.hoge3,f.fuga1,f.fuga2,f.fuga3 
from 
  HOGE h,FUGA f 
where 
  h.hoge1(+) = f.fuga1

```

#### 左外部結合

```sql
select 
  h.hoge1,h.hoge2,h.hoge3,f.fuga1,f.fuga2,f.fuga3 
from 
  HOGE h,FUGA f 
where 
  h.hoge1 = f.fuga1(+)

```
これは **(+)** を付けた方のデータがなくても空行を返すという動きをします。



## ビジュアルでイメージ

テーブルの形を使うと分かりやすいのでそれで書きます。

#### HOGE

|hoge1|hoge2|hoge3|
|:---:|:---:|:---:|
|a|田中|男|
|b|高橋|男|
|d|鈴木|女|
|f|山田|男|


#### FUGA

|fuga1|fuga2|fuga3|
|:---:|:---:|:---:|
|a|総務|課長|
|b|総務|係長|
|c|人事|部長|
|e|人事|課長|

社員情報と部署役職情報を紐づけるものであると考えてください（たとえが悪くてすみません）。

右外部結合のSQLの場合、 **hoge1** がなくても返すという動きなので

|hoge1|hoge2|hoge3|fuga1|fuga2|fuga3|
|:---:|:---:|:---:|:---:|:---:|:---:|
|a|田中|男|a|総務|課長|
|b|高橋|男|b|総務|係長|
||||c|人事|部長|
||||e|人事|課長|

こんな感じ。

左外部結合のSQLの場合 **fuga1** がなくても返すという動きなので

|hoge1|hoge2|hoge3|fuga1|fuga2|fuga3|
|:---:|:---:|:---:|:---:|:---:|:---:|
|a|田中|男|a|総務|課長|
|b|高橋|男|b|総務|係長|
|d|鈴木|女||||
|f|山田|男||||

こんな感じ。





# 推奨の書き方

では非推奨なので上記で紹介した **左外部結合** 、 **右外部結合** 、にくわえ**完全外部結合**をの形3つの推奨の書き方を紹介します。


## 完全外部結合

|hoge1|hoge2|hoge3|fuga1|fuga2|fuga3|
|:---:|:---:|:---:|:---:|:---:|:---:|
|a|田中|男|a|総務|課長|
|b|高橋|男|b|総務|係長|
||||c|人事|部長|
|d|鈴木|女||||
||||e|人事|課長|
|f|山田|男||||

このように取得できる **完全外部結合** は以下のように記述します。

```sql
select
    h.hoge1, h.hoge2, h.hoge3, f.fuga1, f.fuga2, f.fuga3 
from 
    HOGE h full outer join FUGA f on h.hoge1 = f.fuga1
```

同様に

#### 右外部結合

```sql
select
    h.hoge1, h.hoge2, h.hoge3, f.fuga1, f.fuga2, f.fuga3 
from 
    HOGE h right outer join FUGA f on h.hoge1 = f.fuga1

```

#### 左外部結合

```sql
select
    h.hoge1, h.hoge2, h.hoge3, f.fuga1, f.fuga2, f.fuga3 
from 
    HOGE h left outer join FUGA f on h.hoge1 = f.fuga1

```

と書けます。

※ちなみに完全外部結合は **(+)** を両方につけても動きません。


非推奨の理由は以下に記載があります。

出典 ：Oracle® Database SQL言語リファレンス　[結合](https://docs.oracle.com/cd/E16338_01/server.112/b56299/queries006.htm)



# 再度整理


#### 右外部結合

非推奨

```sql
select 
  h.hoge1,h.hoge2,h.hoge3,f.fuga1,f.fuga2,f.fuga3 
from 
  HOGE h,FUGA f 
where 
  h.hoge1(+) = f.fuga1

```

推奨

```sql
select
    h.hoge1, h.hoge2, h.hoge3, f.fuga1, f.fuga2, f.fuga3 
from 
    HOGE h right outer join FUGA f on h.hoge1 = f.fuga1

```


#### 左外部結合

非推奨

```sql

select 
  h.hoge1,h.hoge2,h.hoge3,f.fuga1,f.fuga2,f.fuga3 
from 
  HOGE h,FUGA f 
where 
  h.hoge1 = f.fuga1(+)

```

推奨

```sql
select
    h.hoge1, h.hoge2, h.hoge3, f.fuga1, f.fuga2, f.fuga3 
from 
    HOGE h left outer join FUGA f on h.hoge1 = f.fuga1

```


# 最後に
最近Oracle触り始めた方、エンジニア1年目みたいな方に参考になればと思います。
これからSQL書く人は **(+)** は絶対使わないことを推奨します。

※補足
SQLのwhere句に使う **「＝」** は数学の **「＝」** と同じで、
左辺と右辺が等価であることを意味するため、 **左右可換** です。