SQLについて

## はじめに
SQLの勉強をしようと思ったので，学んだことをまとめていきます．随時更新（多分）  
ミス等があれば，コメントして頂けると幸いです．

# データベースとは
テキストや数値などのデータを保存するためのツール．例えば，TwitterなどのSNSでは「投稿データ」，楽天やAmazonなどのショッピングサイトでは「顧客の購買データ」をデータベースに保管しています．

## 仕組み
データベースは下図のような表でデータを管理している．この表を**テーブル**,列を**カラム**,行を**レコード**と呼びます．テーブルは必要に応じて複数作成可能です．


![データベースの構造](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391440/0a502647-270a-7bdd-9003-fa08e68298f6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391440/c2560318-edf4-3b92-5f18-bb113a1d9e35.png)

# クエリ
データベースからデータを取得するには，データベースに**クエリ**と呼ばれる命令を送る必要があります．SQLはクエリを書くための言語のことです．
クエリは1行で書くこともできますが，読みやすいように改行して書くことにします．
また，SQLは大文字と小文字を区別しないため，**小文字でも問題ありません**．（だからついつい小文字で書いてしまう…）

## データを取得する
**SELECT文**を使って**どのカラムのどのデータを取得するか**を選びます．

```sql:test.sql
SELECT name;
```
## 複数のテーブルが存在する場合
**FORM**を用いて**SELECT**で選んだカラムが**どのテーブルのカラムか**を指定する必要があります．

```sql:test.sql
SELECT name
FROM people;
```

## 複数のカラムからデータを取得する
カラム名をカンマ[ , ]区切りで書きます．

```sql:test.sql
SELECT name, type;
```
## 全てのカラムからデータを取得する
＊の記号を使います．

```sql:test.sql
SELECT *
FROM people;
```

## 特定のデータだけ取得する
**WHERE**を使って**どこのレコード（行）を取得するか**を指定します．
カラムのデータがテキストデータ，日付データの場合にはクォーテーション[ " or ' ]で囲む必要があります．
数値データの場合は囲む必要がありません．
※データ型については他にもありますが，今回は以上の3つを対象にしています．

```sql:test.sql
SELECT *
FROM people
WHERE category = "大人";　# テキストデータ，日付データ
------------------------------------------------
WHERE height = 150; # 数値データ
```

## 比較演算子
```sql:test.sql
SELECT *
FROM people
WHERE height < 150; # 150より小さいデータを検索
------------------------------------------------
WHERE height <= 150; # 150以下のデータを検索
------------------------------------------------
WHERE height > 150; # 150より大きいデータを検索
------------------------------------------------
WHERE height >= 150; # 150以上のデータを検索
```
比較演算子は数値データ以外にも，日付データにも使用可能です．

```sql:test.sql
SELECT *
FROM people
WHERE height < "2020-01-01"; # 2020-01-01以前のデータを検索
```

## ある文字を含むデータの検索
**LIKE演算子**を使用して，**指定したカラムが「カレー」を含むレコード**を指定します．

```sql:test.sql
SELECT *
FROM people
WHERE food LIKE "カレー";
```
### ワイルドカード
「カレー」を含むどんな文字列にも一致するものを検索できます．

```sql:test.sql
SELECT *
FROM people
WHERE food LIKE "%カレー%";
===============================
カレー， 焼きカレー， カレーライス， カツカレーライス
```
### 前方一致
「カレー」以降だけどんな文字列にも一致するものを検索できます．

```sql:test.sql
SELECT *
FROM people
WHERE food LIKE "%カレー";
===============================
カレー， 焼きカレー
```

### 後方一致
「カレー」より前はどんな文字列にも一致するものを検索できます．

```sql:test.sql
SELECT *
FROM people
WHERE food LIKE "カレー%";
===============================
カレー， カレーライス
```
## 否定の条件
**NOT演算子**を使用して， **「カレー」を含まないデータ**や**「カレー」に一致しないデータ**を取得できます．

```sql:test.sql
SELECT *
FROM people
WHERE NOT height < 150; # 150より小さいデータではない（150以上のデータ）を取得
-----------------------------------------------------------------------
WHERE NOT food LIKE "%カレー%"; # 「カレー」を含まないデータを取得
```

## NULLデータ
**NULL**は**中身が何か分からないデータ**のことです．
何のデータも保存されていない場合などが該当します．

### NULLのデータを取得する
指定したカラムがNULLであるレコードデータを取得します．

```sql:test.sql
SELECT *
FROM people
WHERE height IS NULL;
```
### NULLではないデータを取得する
指定したカラムがNULLでないレコードデータを取得できます．

```sql:test.sql
SELECT *
FROM people
WHERE height IS NOT NULL;
```
※NULLデータを取得したい時に，イコール[ = ]を使うことはできません．

## AND演算子
WHEREに複数の条件を指定することができます．
以下のようにすることで，2つの条件を共に満たすデータを検索することができます．

```sql:test.sql
SELECT *
FROM people
WHERE category = "大人"
AND age >= 40;
```
## OR演算子
AND演算子と同様に，複数の条件を指定することができます．
以下のようにすることで，2つの条件のうちどちらかを満たすデータを検索することができます．

```sql:test.sql
SELECT *
FROM people
WHERE category = "大人"
AND age <= 40;
```

## データの並び替え
**ORDER BY**を使って．**並べ替えたいカラム**と**並べ方**を指定します．
**ASC**（昇順）：1, 2, 3, …, 100

```sql:test.sql
SELECT *
FROM people
ORDER BY height ASC;
```

**DESC**（降順）：100, 99, 98, …, 1

```sql:test.sql
SELECT *
FROM people
ORDER BY height DESC;
```
どちらも**where**と併用が可能です．

```sql:test.sql
SELECT *
FROM people
WHERE category = "大人"
ORDER BY height ASC;
-----------------------
ORDER BY height DESC;
```
## 取得するデータ数の制限
**LIMIT**を使って，取得するデータの件数を指定します．

```sql:test.sql
SELECT *
FROM people
LIMIT 10;
```
**ORDER BY**と同様に**WHERE**と併用が可能です．

```sql:test.sql
SELECT *
FROM people
WHERE category = "大人"
LIMIT 10;
```
## 重複したデータを除く
**DISTINCT (カラム名)**を使って，検索結果から指定したカラムの重複するデータを除くことができます．

```sql:test.sql
SELECT DISTINCT(name)
FROM item;
```
## 四則演算
+:足す
-:引く
*:かける
/:割る

```sql:test.sql
SELECT name, price * 1.08
FROM item;
```
## 集計関数
合計，平均などを求めることができます．
### 合計
**SELECT**で取得するカラムに使用することで，合計を取得できます．

```sql:test.sql
SELECT SUM(price)
FROM item;
```
**WHERE**と併用できます．

```sql:test.sql
SELECT SUM(price)
FROM item
WHERE name = 'Aさん';
```

### 平均
**SELECT**で取得するカラムに使用することで，平均を取得できます．

```sql:test.sql
SELECT AVG(price)
FROM item;
```
**WHERE**と併用できます．

```sql:test.sql
SELECT AVG(price)
FROM item
WHERE name = 'Aさん';
```

### データ数を数える
**SELECT**で取得するカラムに使用することで，指定したカラムの合計数を取得できます．
**しかし，NULLになっているデータはカウントされません**.

```sql:test.sql
SELECT COUNT(price)
FROM item;
```
NULLも含めてデータ数を計算したいときは， **COUNT(*)**（全てのカラム）を指定します．

```sql:test.sql
SELECT COUNT(*)
FROM item;
```
**WHERE**と併用できます．

```sql:test.sql
SELECT COUNT(*)
FROM item
WHERE name = 'Aさん';
```

### 最大・最小
**SELECT**で取得するカラムに使用することで，最大のデータ，最小のデータを取得できます．

### 最大
```sql:test.sql
SELECT MAX(price)
FROM item;
```
**WHERE**と併用できます．

```sql:test.sql
SELECT MAX(price)
FROM item
WHERE name = 'Aさん';
```

### 最小
```sql:test.sql
SELECT MIN(price)
FROM item;
```
**WHERE**と併用できます．

```sql:test.sql
SELECT MIN(price)
FROM item
WHERE name = 'Aさん';
```

## データのグループ化
**GROUP BY**を使用することで，日付ごと，人ごとに金額の合計を算出することができます．
※SELECTで使えるのは**GROUP BYに指定しているカラム名と集計関数だけ**です．

```sql:test.sql（正解）
SELECT SUM(price), date
FROM item
GROUP BY date;
```
以下では，SELECTで集計関数を使用していないため，日付ごとに集計された値が取得できません．

```sql:test.sql（間違い）
SELECT price, date
FROM item
GROUP BY date;
```

### 複数カラムのグループ化
絡む名をカンマ[ , ]でつなげることで，複数のカラム名を適用させることができます．
複数のカラム名でグループ化すると，データの組み合わせの数だけグループができます．
例：「Aさん」の「2020-01-01」のグループ， 「Bさん」の「2020-01-02」のグループ, etc…

```sql:test.sql
SELECT SUM(price), date, name
FROM item
GROUP BY date, name;
```
集計関数を使用することで，各グループごとにデータを集計できます．
例：日付と人ごとの金額の合計， 日付と人ごとの購入数， etc…

### より細かい条件でグループ化
**WHERE**と併用できます．
実行順は，上から

| 検索 | WHERE |
|:---:|:---:|:---:|
| グループ化 | GROUP BY | 
| 関数 | COUNT・SUN・AVG・MAX・MIN |

のようになっています．  
そのため，日付と人ごとの食事に使ったお金の合計を取得するときは，
1. **WHERE**でカテゴリが「食品」であるレコードを検索
2. 日付とキャラクターでグループ化する
3. 集計関数で集計する

という順番で行います．

```sql:test.sql
SELECT SUM(price), date, name
FROM item
WHERE category = '食品'
GROUP BY date, name;
```

### さらに絞り込む
**HAVING**を使用することで，条件を満たすグループを取得できます．
HAVINGはグループ化された後のテーブルから検索するため，条件文で使用するカラムは必ず**グループ化されたテーブルのカラム**を使用します．

```sql:test.sql
SELECT SUM(price), date
FROM item
GROUP BY date
HAVING SUM(price) > 2000;
```
グループ化した後のデータを絞り込む際にWHEREではなくHAVINGを使用するのは，以下の実行順によるためです．

| 検索 | WHERE |
|:---:|:---:|:---:|
| グループ化 | GROUP BY | 
| 関数 | COUNT・SUN・AVG・MAX・MIN |
| HAVING | HAVING |

WHERE:検索対象がグループ化される前の**テーブル全体**
HAVING:検索対象が**GROUP BY**によって**グループ化されたデータ**





## 2020 04 01 ~ 04 02
データベースとは 〜 否定の条件
## 2020 04 02 ~ 04 03
NULLデータ ~ データのグループ化

## 参考
[Progate](https://prog-8.com/)
[フリーイラスト素材集 ジャパクリップ](https://japaclip.com/)