【HAVING句】#6 Webディレクター見習いが知識ゼロからSQLを学ぶ

こんにちは! 　saku-chanです!
このアカウントは、社会人1年目のWebディレクター見習い(初心者)がSQLを学ぶ成長記録になっています。
ひよっこから成長する過程を残し、ついでに皆さんからアドバイスを頂けたら良いな! 私と同じように知識ゼロからSQLを始める人の一つの指針になればいいな!という思いで作成しました。
ちなみに、ブログを含め記事などを書いた経験がないため読みづらい部分も多々あるかと思いますが、そこも含めて皆さまアドバイス頂けると嬉しいですmm

◆記事の内容は、**SQL初心者の自分が、同じような初心者の方でも理解しやすいように心がけながら、SQLの基本に関して学んだことを懇切丁寧に**記載しています◆

##目次
- [はじめに](https://qiita.com/saku-chan/items/30de684ae6d0d8aae084#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)
- [HAVING句とは](https://qiita.com/saku-chan/items/30de684ae6d0d8aae084#having%E5%8F%A5%E3%81%A8%E3%81%AF)
<br>└[HAVING句とWHERE句の違い](https://qiita.com/saku-chan/items/30de684ae6d0d8aae084#having%E5%8F%A5%E3%81%A8where%E5%8F%A5%E3%81%AE%E9%81%95%E3%81%84)
- [まとめ](https://qiita.com/saku-chan/items/30de684ae6d0d8aae084#%E3%81%BE%E3%81%A8%E3%82%81)
- [最後に](https://qiita.com/saku-chan/items/30de684ae6d0d8aae084#%E6%9C%80%E5%BE%8C%E3%81%AB)

##はじめに
今回はSQLのSELECT文で使用される`HAVING句`に関して勉強したことを記載します！
HAVING句は自分が結構混乱した句なので、自分がつまづいた点を意識しながら、書いていければと思います。
初めてSQLを勉強する方が気軽に読んでいただける記事になっていますよ^^
ではスタート!

⇒[前回の記事【GROUP BY句】はこちら](/saku-chan/items/951d36e75bfce3fbcb1f)
⇒[前々回の記事【WHERE句】はこちら](/saku-chan/items/9cfe22decee081848772)

⇒[記事一覧](/saku-chan/items/48d36b6ad60d63206a18)

##HAVING句とは
`HAVING句`とはなんでしょうか？
`HAVING句`は`GROUP BY句`でグループ化した結果に対し、データを絞り込むために使用します。

まずは[前回の記事](/saku-chan/items/951d36e75bfce3fbcb1f)で書いた`GROUP BY句`を使ってデータを分類してみます。
使用するテーブルとクエリは以下の通りです。

Table名：quiz_2

|number|area | team_name|points|
|:-------------:|:-------------:|:------------:|:------------:|
|01| 東京| スマイル |2|
|02| 大阪|  たこ焼き |3|
|03|  東京 |  乃木坂 |1|
|04| 福岡 |  わんちーむ  |3|
|05|大阪 | しらんけど|7|
|06|  東京 |  ガールズ4 |3|
|07| 愛知| しゃちほこ  |4|

```sql
SELECT area,
　　　　AVG(points) AS 平均得点 
FROM quiz_2 
GROUP BY area;
```
このクエリの実行結果は下記のようになります。

|area |平均得点|
|:-------------:|:-------------:|
| 東京|2|
| 大阪|5|
| 福岡|3|
| 愛知| 4|

areaに分けて、それぞれのエリアの平均得点を求めることが出来ていますね。
ここまでは前回のおさらいでした。

では、今回は新たに`HAVING句`を使用してさらにデータを絞り込んでみます。

```sql
SELECT area AS 地域,
       AVG(points) AS 高得点
FROM quiz_2 
GROUP BY area
HAVING  AVG(points) >= 4 ;
```
このクエリを実行すると、先ほどの結果から、さらに平均得点が4点以上のもののみに絞ることが出来ます。

|地域|高得点|
|:-------------:|:-------------:|
| 大阪|5|
| 愛知| 4|

このように`HAVING句`と`GROUP BY句`を使用することでより複雑な絞り込みを行うことが出来るんですね!

さあここで少し不思議に思われた方がいるかもしれません。

あれ? 行を絞り込むための句ってもう1つあったよね?

そうなんです!
`WHERE句`も行を絞り込むために使われるものでした。

この部分で自分は混乱してしまったので、丁寧に解説していきたいと思います。

###HAVING句とWHERE句の違い
まず結論からお伝えすると、
**`HAVING句`にはCOUNT関数などの集約関数を書くことが出来ます**が、`WHERE句`には書くことができません。
また、内容によっては`WHERE句`でも`HAVING句`でも書くことが出来る場合がありますが、その場合は**`WHERE句`に書く**のがベターです。

たとえば、`WHERE句`でも`HAVING句`でも書くことが出来る場合に下記のような場合があります。

Table名：quiz_2

|number|area | team_name|points|
|:-------------:|:-------------:|:------------:|:------------:|
|01| 東京| スマイル |2|
|02| 大阪|  たこ焼き |3|
|03|  東京 |  乃木坂 |1|
|04| 福岡 |  わんちーむ  |3|
|05|大阪 | しらんけど|7|
|06|  東京 |  ガールズ4 |3|
|07| 愛知| しゃちほこ  |4|

```sql
SELECT area,
       AVG(points) AS 平均得点
FROM quiz_2 
WHERE area = '東京'
GROUP BY area
;
```


```sql
SELECT area,
       AVG(points) AS 平均得点
FROM quiz_2 
GROUP BY area
HAVING  area = '東京' ;
```

どちらのクエリを実行しても、結果としては下記のようにareaカラムが東京の平均得点を求めることが出来ます。

|area |平均得点|
|:-------------:|:-------------:|
| 東京|2|

このようにどちらでも記述可能なのですが、**SELECT文の処理の順番の関係**で、`WHERE句`で絞ることが出来るものは`WHERE句`での絞り込みが推奨されます。

なになに!いきなり、順番なんて覚えれないよ!
って思った方、安心してください
**SELECT句以外は記述した順に上から処理されていく**ので、SELECT句の位置だけ覚えれば大丈夫です!

表にまとめると以下の通りになります。

|句|記述順|処理順|
|:-------------:|:-------------:|:-------------:|
| SELECT|1|**5**|
|FROM|2|1|
|WHERE|3|2|
|GROUP BY|4|3|
|HAVING|5|4|
|ORDER BY|6|6|
|LIMIT|7|7|

このように、`HAVING句`よりも先に`WHERE句`が処理されるため、
結果が同じになる場合は、`WHERE句`に記述するほうが早い段階でデータ量が削減されることになります。
データ量が多いと、記述順によるシステム処理の差が大きくなるため`WHERE句`への記述を優先するんですね。

##まとめ
- `HAVING句`は`GROUP BY句`でグループ化した結果に対し、データを絞り込むために使用する
- `HAVING句`にはCOUNT関数などの集約関数を書くことが出来るが、`WHERE句`には書くことができない
- `WHERE句`でも`HAVING句`でも書くことが出来る場合は`WHERE句`に記述する

##最後に
今回は`HAVING句`に関してまとめてみました！
最近はちゃんと、それぞれの句での処理後のデータをイメージしながら記述するようにしています(゜゜)
(今まで何も考えずに書いてたのがバレますね、、><笑)
ではまた次回!

⇒[記事一覧](/saku-chan/items/48d36b6ad60d63206a18)