【SQL】基本的な書き方

SQL初心者が、勉強しながら覚書としてまとめた記事です。

# 基本の理解

テキストや数値などのデータを保存するためのツールである「データベース」は、「テーブル（表）」でデータを管理しており、縦の列のことを「カラム」、横の行のことを「レコード」と呼ぶ。

データベースからデータを取得するためには、命令（クエリ）を送る。
SQLは、その命令（クエリ）を書くための言語。


# SQLの基本的な書き方

- コメント...`--`に続けて書く

#### データベースからデータを取得する

- `SELECT` ...どのカラムのデータを取得するかを指定（全ての場合は `*`）
- `FROM` ...どのテーブルのカラムから取得するかを指定

```sql
SELECT カラム名１, カラム名２
FROM テーブル名;
```

※SQLは大文字と小文字を区別しない。

#### 特定のデータを取得する（WHERE）

`WHERE` で、どこのレコードからデータを取得するかを指定する。

```sql
SELECT *
FROM テーブル名
WHERE カラム名 = "値";
```
※数値は""で囲わないが、日付は囲う必要がある。

#### 比較演算子を使う

SQLでは、比較演算子を利用して取り出すデータを指定することができる。

書き方の例。purchasesテーブルから、priceカラムが1000円以上のデータを取得する。

```sql
SELECT *
FROM purchases
WHERE price >=1000;
```

#### ある文字を含むデータを指定する（LIKE演算子）

- `LIKE` を使うことで、指定したカラムがある値のデータを持つレコードからデータを取得することができる。
- `%文字列%`（ワイルドカード）...指定した文字列を含む全てのデータ
- `文字列%`（前方一致）...指定した文字列から始まるデータ
- `%文字列`（後方一致）...指定した文字列で終わるデータ


書き方の例。nameカラムに「プリン」を含むデータを全て取得する。

```sql
SELECT *
FROM purchases
WHERE name LIKE "%プリン%";
```

#### NOT演算子を使う

WHEREの後に `NOT` をつけると、「〇〇を含まないデータ」や「〇〇に一致しないデータ」のような条件になる。

書き方の例。priceカラムが1000円以上“でない”データを取得する。

```sql
SELECT *
FROM purchases
WHERE NOT price >=1000;
```

#### 空のデータを取得する（NULL）

- `IS NULL` ...カラムが空のレコードからデータを取得
- `IS NOT NULL` ...カラムが空でないレコードからデータを取得

書き方の例。priceカラムが空でないデータを取得する。

```sql
SELECT *
FROM purchases
WHERE price IS NOT NULL;
```

#### 複数の条件で指定する（AND演算子・OR演算子）

以下を使って、WHEREに複数の条件を指定することができる。

- `AND` ...複数の条件すべてを満たすデータを取得
- `OR` ...複数の条件のいずれかを満たすデータを取得

書き方の例。カテゴリーが"食費"で、かつ、character_nameが"猫"のデータを取得する。

```sql
SELECT *
FROM purchases
WHERE category="食費" AND character_name="猫";
```

#### データを並び替える（ORDER BY）

`ORDER BY` をクエリの末尾に記述することで、データの取得結果を並び替えることができる。

- `ASC` ...昇順
- `DESC` ...降順

```sql
ORDER BY 並べ替えたいカラム名 並べ方;
```

書き方の例。character_nameが"猫"のデータを取得し、priceカラムを基準に昇順に並べ替える。

```sql
SELECT *
FROM purchases
WHERE character_name = "猫"
ORDER BY price ASC;
```

#### 取得するデータの件数を制限する（LIMIT）

`LIMIT` をクエリの末尾に記述することで、最大で何件取得するかを指定することができます。

```sql
LIMIT データの件数;
```

書き方の例。character_nameが"猫"のデータをpriceを降順に並べ替えた上で、5件目までを取得する。

```sql
SELECT *
FROM purchases
WHERE character_name = "猫"
ORDER BY price DESC
LIMIT 5;
```



# 検索結果を加工する

#### 重複したデータを省く（DISTINCT）

`DISTINCT(カラム名)` で、検索結果から指定したカラムの重複するデータを除くことができる。


書き方の例。重複を除いた状態でnameカラムのデータを取得する。

```sql
SELECT DISTINCT(name)
FROM purchases;
```

#### 四則演算を使う

SQLでは、+（足す）, -（引く）, *（掛ける）, /（割る）を使って、取得したデータを加工することができる。

書き方の例。nameカラムとpriceカラムのデータを取得し、priceは消費税込みの金額にする。

```sql
SELECT name, price * 1.08
FROM purchases;
```

#### 合計を計算する（SUM）

`SUM(カラム名)` を使って、取得したデータの合計を求めることができる。

書き方の例。character_nameが"猫"のpriceデータを取得して合計を求める。

```sql
SELECT SUM(price)
FROM purchases
WHERE character_name = "猫"
;
```

#### 平均を計算する（AVG）

`AVG(カラム名)` を使って、取得したデータの平均を求めることができる。

書き方の例。character_nameが"猫"のpriceデータを取得して平均を求める。

```sql
SELECT AVG(price)
FROM purchases
WHERE character_name = "猫"
;
```

#### データの数を求める（COUNT）

`COUNT(カラム名)` を使って、データの数を求めることができる。

nullの数も含めてレコードの数を計算したい場合は、`COUNT(*)` とする。
※そのままだとnullのデータの数は計算されない。

書き方の例。character_nameが"猫"のpriceデータの数（nullを含む）を求める。

```sql
SELECT COUNT(*)
FROM purchases
WHERE character_name = "猫"
;
```

#### 最大・最小を求める（MAX・MIN）

`MAX(カラム名)` や `MIN(カラム名)` を使って、データの最大値、最小値を求めることができる。

書き方の例。character_nameが"猫"のpriceデータの最大値を求める。

```sql
SELECT MAX(price)
FROM purchases
WHERE character_name = "猫"
;
```


# グループ化する（GROUP BY）

FROMの後ろに `GROUP BY カラム名` を追記すると、指定したカラムで同一のデータを持つレコードがグループとなり、集計関数により、各グループごとにデータが集計される。

※GROUP BYを使う場合、SELECTで使えるのは、GROUP BYに指定しているカラム名と、集計関数のみ。

書き方の例。purchased_atでグループ化し、買い物をした日付ごとにお金を使った回数を取得する。

```sql
SELECT COUNT(price), purchased_at
FROM purchases
GROUP BY purchased_at
;
```

#### 複数のカラムを使ってグループ化する（GROUP BY）

`GROUP BY` の後カンマ（,）を挟んで複数のカラム名を入れることで、複数のカラムを使ってグループ化することができる。

書き方の例。purchased_atとcharacter_nameでグループ化し、日付とキャラクターごとに使ったお金の合計額を取得する。

```sql
SELECT SUM(price), purchased_at, character_name
FROM purchases
GROUP BY purchased_at, character_name
;
```


#### 細かい条件でグループ化する

`GROUP BY` と `WHERE` を併用し、さらに細かい条件でグループ化することができる。
※`GROUP BY` は `WHERE` の後に書く。

書き方の例。categoryが"食費"であるデータを取得した上で、purchased_atとcharacter_nameでグループ化し、日付とキャラクターごとに使ったお金の合計額を取得する。

```sql
SELECT SUM(price), purchased_at, character_name
FROM purchases
WHERE category = "食費"
GROUP BY purchased_at, character_name
;
```

#### グループ化したデータを更に絞り込む（HAVING）

`GROUP BY` でグループ化したデータから、更に特定のグループのみを取得する場合は `HAVING` を使う。

`WHERE` はグループ化される前のテーブル全体を検索対象とするのに対し、`HAVING` は `GROUP BY` によってグループ化されたデータを検索対象とする。

```sql
GROUP BY カラム名
HAVING 条件;
```

書き方の例。purchased_at（日付）でグループ化し、priceの合計額が2000円を超えるデータの合計額と日付を取得する。

```sql
SELECT SUM(price), purchased_at
FROM purchases
GROUP BY purchased_at
HAVING SUM(price) > 2000
;
```


# サブクエリを使う

SQLでは、クエリの中に他のクエリを入れることができ、この他のクエリをサブクエリと言う。
2つ以上のクエリを1つにまとめることができるので、より複雑なデータを取得する際に使われる。


#### サブクエリの書き方

`( )`で囲むことで、サブクエリを使用する。
※()内にはセミコロン（;）は不要。

書き方の例。平均得点数を出し、それより得点数が多い選手名と得点数を取得する。

```sql
SELECT name,goals
FROM players
WHERE goals > (
  SELECT AVG(goals)
  FROM players
);
```

#### カラム名に別名を定義する（AS）

`AS`を使うことでカラム名などに別名を定義し、取得したデータが何なのかをわかりやすくすることができる。

```sql
カラム名 AS "名前"
```

書き方の例。チームの合計得点数を取得し、カラム名を"チームの合計得点"とする。

```sql
SELECT SUM(goals) AS "チームの合計得点"
FROM players
;
```


# 複数のテーブルを活用する

複数のテーブルを一緒に使うためには、「主キー」・「外部キー」が設定されたカラムを用意する必要がある。

#### テーブルの結合（JOIN）

紐付いたテーブル同士は `JOIN` を使うことで合体させることができる。
結合したテーブルは1つのテーブルと同じようにデータを取得することができる。

```sql
SELECT *
FROM テーブルA
JOIN テーブルB
ON テーブルA.カラム名 = テーブルB.カラム名;
```

書き方の例。playerテーブルにcountriesテーブルを結合し、playerテーブルのcountry_idカラムとcountriesテーブルのidカラムを紐付ける。

```sql
SELECT *
FROM players
JOIN countries
ON players.country_id = countries.id;
```

#### 複数テーブルでのカラムの指定

複数のテーブルに同じカラム名が存在するときは、`テーブル名.カラム名` で指定する。

書き方の例。playerテーブルにcountriesテーブルを結合し、playersテーブルのnameカラムとcountriesテーブルのnameカラムを取得する。

```sql
SELECT players.name, countries.name
FROM players
JOIN countries
ON players.country_id = countries.id
;
```

#### NULLを含めて取得（LEFT JOIN）

JOINは外部キーがNULLであるレコードを取得しないが、`LEFT JOIN` を使うことにより、NULLのレコードも実行結果に表示できる。
（NULLの部分は空白となって表示される）

書き方の例。playerテーブルにteamsテーブルを結合し、NULLも含めたデータを取得する。

```sql
SELECT players.name AS "選手名", teams.name AS "前年所属していたチーム"
FROM players
LEFT JOIN teams
ON players.previous_team_id = teams.id
;
```

#### 3つ以上のテーブルを結合する

JOINを複数回使うことで、3つ以上のテーブルを結合することができる。

書き方の例。playerテーブルにcountriesテーブルとteamsテーブルを結合し、データを取得する。

```sql
SELECT *
FROM players
JOIN countries
ON players.country_id = countries.id
LEFT JOIN teams
ON players.previous_team_id = teams.id
;
```

# 実行される順序

上から順に実行される。

- テーブルの指定（FROM）
- 結合（ON, JOIN）
- 取得条件（WHERE）
- グループ化（GOUP BY）
- 関数（COUNT, SUM, AVG, MIN）
- HAVING（HAVING）
- 検索（SELECT, DISTINCT）
- 順序（ORDER BY）
- LIMIT（LIMIT）



# 最後に
2億年前にProgateで基礎だけやって止まっていたのですが、この記事↓を読んで勉強再開する気がおきました。ありがとうございます。

[サービスデザイナーがSQLを学んだら利点だらけだった話](https://qiita.com/chosan_/items/bf97476eb6fe96d9356c)


#### 参考にさせてもらったサイトなど
- [Progate / SQL（I, II, III）](https://prog-8.com/languages/sql)