SQLの基本を学ベる入門書で0から学んでみた

## はじめに
本記事は私自身が書籍を用いて学んだことに関する備忘録であることをご理解ください。
SQLやデータベースについて、基礎的な部分から学んでみたいと思い、「スッキリわかるSQL入門」という書籍で学習をしてみました。

### きっかけ
Railsを書くことが多いのですが、RailsのModelにActiveRecordが適用されているおかげで、データベースから簡単にデータを出し入れすることが可能です。
一方で、このActiveRecordがあまりにも優秀なため、SQLをそこまで理解していなくとも、データの出し入れができてしまっている状態でした。
言わば、実装する上でどんなSQL文が発行されているかを意識しないでも実装ができてしまっていたのが個人的に感じた課題感です。

本質的には、SQLをきちんと理解できていることでパフォーマンス観点だけでなく、コードの品質を保つことができると考えたため、SQLの機能を正確に使えるようになりたいなと思ったことが始まりでした。

## データベースを使う立場
SQLはデータベースを操作するための言語ですが、大きく2つの立場が存在します。

1. テーブルをはじめとしたデータベースを作る側の人間
1. データベースにデータを入れたり出したりする側の人間

1の場合はデータ定義言語(Data Definition Language)を扱い、以下のようなことをします。
- テーブルの作成
- テーブルの削除
- テーブルへのカラム追加
- テーブルへのカラム削除
- 制約等の設定

2の場合はデータ操作言語(Data Manipulation Language)を扱い、以下のようなことをします。
- データの登録
- データの抽出
- データの更新
- データの削除

本記事では、1→2の順番で簡単にまとめようと思います。

## ①SQLでテーブルを操作する

### テーブルの作成
```
CREATE TABLE テーブル名(
    カラム名 カラムの型 オプション,
    カラム名 カラムの型 オプション
)
```


#### オプション
主なオプションの例は以下になります。
- NOT NULL
    - nullを許可しないオプション
- PRIMARY KEY
    - 主キーを設定するオプション
- DEFAULT
    - デフォルト値を設定するオプション

例えば、fruitテーブルを作成する場合はこんな感じ
```
CREATE TABLE fruit(
    ID   INTEGER      PRIMARY KEY,     #PRIMARY KETオプション
    NAME VARCHAR(40)  NOT NULL,        #NOT NULLオプション
    MEMO VARCHAR(100)  DEFAULT '不明',  #DEFAULTオプション
)
```
※通常だと`NOT NULL`制約は`DEFAULT`指定と組み合わせて使われることがほとんどですが、便宜上このような記載にしてます

### テーブルの削除
```
DROP TABLE テーブル名

（fruitテーブルを削除したい場合は以下で消える）
DROP TABLE fruit
```

### カラムの追加
```
ALTER TABLE テーブル名 ADD カラム名　カラムの型

（fruitテーブルにカラム名PRICE, 型はINTEGERを定義したい場合は以下で追加）
ALTER TABLE fruit ADD PRICE　INTEGER
```

### カラムの削除
```
ALTER TABLE テーブル名 DROP カラム名

（fruitテーブルのカラム名PRICEを削除したい場合は以下で消える）
ALTER TABLE fruit DROP PRICE
```

## ②SQLでデータを操作する
SQLでデータ操作を行う際は、4つの命令だけで操作を完結することができます。

1. SELECT（データを検索する） 
1. INSERT（データを追加する） 
1. UPDATE（データを更新する） 
1. DELETE（データを削除する） 

### SELECT（データを検索する） 
```
SELECT カラム名, カラム名
FROM テーブル名
(where条件)
(その他の修飾)
```
※修飾の部分は必要な時に指定します

### INSERT（データを追加する） 
```
INSERT INTO テーブル名 (カラム名, カラム名,　カラム名)
VALUES (値, 値, 値)
```
※テーブルの全てのカラムに値を指定する場合は、`（カラム名, カラム名,　カラム名）`は省略可能です

### UPDATE（データを更新する） 
```
UPDATE テーブル名
SET カラム名 = 値, カラム名 = 値
where 条件
(カラム名はカンマで区切ることで複数指定可能です)
```
※`where`がない`UPDATE`は全てのレコードが更新されてしまうため、注意してください

### DELETE（データを削除する） 
```
DELETE FROM テーブル名
where 条件
```
※`where`がない`DELETE`は全てのレコードが削除されてしまうため、注意してください

### SQLで操作するデータを絞り込む
1つ前の章で`where`というものが出てきました。
`where`を使わないと、全てのレコードが更新されてしまったり、削除されてしまったりするのですが、この`where`は処理の対象となるデータを絞り込むことのできる修飾語です。

基本的に、`SELECT`・`UPDATE`・`DELETE`で使用可能となっています。

```
where 条件式
```
上記が基本構文でとてもシンプルではありますが、`TRUE`か`FALSE`の結果となる条件式しか指定できない点は注意してください。

例えば、
`where name = 'いちご'`
これであれば、nameカラムが「いちご」かどうか？なので、`TRUE`もしくは`FALSE`が返ってきます。
nameカラムに「いちご」が存在する場合は、条件式を満たしている（TRUE）ので、そのデータで絞り込まれます。

一方、以下の場合では返ってくるデータが数値になるため、`TRUE`でも`FALSE`でもありません。
`where price + 100`
このように、結果が数値や文字列になるものはwhereの条件式に記述できないため、注意してください。

`where`を使って対象のデータを絞り込むのですが、以下のようなものと組み合わせて使用することが多いです。
- 比較演算子
    - `=` `<` `>` `IS NULL` `ANY` `BETWEEN`
- 論理演算子
    - `AND` `OR` `NOT`

### SQLで抽出した結果を加工する
`where`を使って対象のデータを絞り込んだ後、その結果を以下のように加工することができます。
- 検索結果を並び替える
- 検索結果の重複データを除外する
- 検索結果から件数を限定する

#### 検索結果を並び替える
```
SELECT カラム名
FROM テーブル名
ORDER BY カラム名 並び順
```
※昇順は`ASC`、降順は`DESC`（並び順を指定しない場合はデフォルトで`ASC（昇順）`になる）

`ORDER BY`では複数カラムを間まで区切って指定できます。
その場合は、まず最初に指定された列で並び替えを行い、同じ値が複数行ある場合には次に指定されたカラムで並び替えが行われます。

#### 検索結果の重複データを除外する
```
SELECT DISTINCT カラム名
FROM テーブル名
```
`DISTINCT`を使うことで、抽出したデータに重複しているものがあれば、その重複を取り除いた形で抽出できます。
データの種類(一覧)を取得したい場合に使われます。

#### 検索結果から件数を限定する
```
SELECT カラム名
FROM テーブル名
ORDER BY カラム名
LIMIT 5
```
検索結果の全データではなく、上位5つなどを抽出することができます。
（例の場合だと5件抽出している）

### SQLで抽出した結果をグループ集計する
```
SELECT グループ化の基準カラム名, 集計関数
FROM テーブル名
GROUP BY グループ化の基準カラム名
```
`GROUP BY`を使うことで、グループごとに集計を行うことができます。

グループ集計の流れは以下になります。
1. `where`によってデータが絞り込まれる
1. 絞り込んだデータを元に、グループごとで検索結果を分類する
1. 各グループを集計し、`SELECT`でカラムを絞り込む

その結果、以下のようにフルーツ名でグループ化された結果を集計することができます。（あくまで一例ですが）
| フルーツ名 | 売上数 |
|:-:|:-:|
| いちご  |  3  |
| なし  |  4 |
| ぶどう |  1 |

### SQLで集計した結果から更に絞り込む
```
SELECT グループ化の基準カラム名, 集計関数
FROM テーブル名
(where修飾)
GROUP BY グループ化の基準カラム名
HAVING 集計結果に対しての絞り込み条件式
```
結果を集計した後に、更に絞り込みたい場合は`HAVING`を使います。
`where`は最初の検索時に絞り込まれるのに対して、`HAVING`は集計後に絞り込むことができます。

### テーブルの結合
コンピュータにとって、テーブルが分割されている方がデータを安全、確実、高速に取り扱いやすいそうです。
一方、人間にとってテーブルが分割されていることで、何がどのデータなのかを把握するのは難しくなります。
テーブルの結合は、複数のテーブルから人間が理解しやすい形の結果表を得るための手段の1つです。

結合することで、複数のテーブルに格納された関連するデータを1つの結果表として取り出すことができます。

#### JOIN
```
SELECT カラム
FROM テーブルA
JOIN テーブルB
ON 両テーブルの結合条件
```

テーブルの結合条件には、以下のような条件を指定します。
`ON テーブルA.カラム名 = テーブルB.カラム名`
そうすることで、結合条件が満たされたデータを1つ1つ繋いで、1つの結果表として返却してくれます。

※結合には`JOIN`だけでなく他にも多くの種類がありますが、ここでは`JOIN`だけの紹介に留めます


## 最後に
「普段使うことの多いRailsだとどうなるか?」を意識しながら学習していましたが、
テーブルの結合の部分に関して理解がまだまだ乏しいなと感じました。

`INNER JOIN`や`OUTER JOIN`等あり、Railsのログでもよく見る部分なので、しっかりキャッチアップしていこうと思います。

今回学習してみて、SQLは慣れるまでが勝負だなと感じました。
最初は読み取れなかったSQLも、一つずつ解消すればゆっくりではあるが理解できるようになってきたため、あとは慣れれば「ここは〇〇してる」というように、解釈スピードも上がっていくと感じています。

とにかく量をこなすことで質は上がっていくと思うので、継続して学習を続けられたらなと思います。

## 参考
https://amzn.asia/d/9PTf5aG