データベースのきほん #6-SQL文の基本

こんにちは、4年目エンジニアの nakaSay です。

本記事では「データベースのきほん」という書籍の内容をかい摘み、いくつかのパートに分けて記事を投稿しています。
本書籍は入門書であり、記事では以下のような内容を取り上げる予定です。気になった方は是非気軽にお立ち寄りください。

1. [データベースの全体像](https://qiita.com/nakaSay/items/2bfec4e0b56e2032db40)
1. [リレーショナルデータベースとは](https://qiita.com/nakaSay/items/a154bc026a13b2f9e256)
1. [データベースに関わるお金の話](https://qiita.com/nakaSay/items/d065b52c6fe55ba3070a)
1. [データベースとアーキテクチャ構成](https://qiita.com/nakaSay/items/a96293ce85f7e92766f0)
1. [DBMS を操作するときの基本知識](https://qiita.com/nakaSay/items/2c393f85ecec752390b8)
1. [SQL文の基本](#sql文の基本)
1. [トランザクションと同時実行制御](https://qiita.com/nakaSay/items/df1073b0ed73d5389e60)
1. [テーブル設計の基礎](https://qiita.com/nakaSay/items/5b157c24f2237981592a)
1. [バックアップとリカバリ](https://qiita.com/nakaSay/items/cd6239ae500594b0784e)


# SQL文の基本
ここでは、DBMSでデータを操作するための言語として用意されているSQLの基本的な使い方について説明していきます。

## SELECT文

SELECT文はデータ取得のためのコマンドで、基本構文は以下の形式です。
```
SELECT 列名 FROM テーブル名 WHERE 条件;
```

例えば、以下のようなコマンドでは、「地区（distinct）が京都（kyoto）のレコード」を全取得することができます。
```
SELECT * FROM city WHERE district='kyoto';
```

条件文では様々な演算子が使用できますが、その評価の優先順位が決まっています。
https://dev.mysql.com/doc/refman/8.0/ja/operator-precedence.html

例えば、以下のようなクエリだと、後ろの AND から評価され、その後に OR が評価されます。
```
SELECT * FROM WHERE 条件A OR 条件B AND 条件C;
```

### SELECT文の応用

- DISTINCT（重複排除）
    - 例：都道府県のみを取得 
```
SELECT DISTINCT district FROM city WHERE countrycode='JPN';
```

- ORDER BY 列1 [, 列2,...]（並び替え）
    - 例：人口の降順に並び替え
        - デフォルトは昇順のASCだが、DESCを指定すると降順となる
```
SELECT * FROM city WHERE countrycode='JPN' ORDER BY population DESC;
```

- GROUP_CONCAT（文字列の集約）
    - 例：都道府県を結合して取得
```
SELECT GROUP_CONCAT(DISTINCT district) FROM city WHERE countrycode='JPN';
```

- GROUP BY（グループに切り分けて集約）
  - 例：都道府県ごとに都市数を取得
```
SELECT district, COUNT(*) FROM city WHERE countrycode='JPN' GROUP BY distrct;
```

- HAVING（集約した値への条件付加）
  - 例：都市数が4の都道府県を取得
```
SELECT district, COUNT(*) FROM city WHERE countrycode='JPN' GROUP BY distrct HAVING COUNT(*)=4;
```

## UPDATE文

UPDATE文はデータを更新するためのコマンドで、基本構文は以下の形式です。
```
UPDATE テーブル名 SET 列名1=値, 列名2=値,...;
```

例えば、以下のようなコマンドでは、「京都（kyoto）の人口（population）」を更新することができます。
```
UPDATE city SET population=1469069 WHERE countrycode='JPN' and district='kyoto';
```

## INSERT文

INSERT文はデータを挿入するためのコマンドで、基本構文は以下の形式です。
```
INSERT INTO テーブル名 (列名1, 列名2,...) VALUES (値, 値,...);
```

例えば、以下のようなコマンドでは、「愛媛（Ehime）の大洲市（Ozu）」を追加することができます。
```
INSERT INTO city (name, countrycode, district, population) VALUES ('Ozu', 'JPN', 'Ehime', 45020);
```

## DELETE文

DELETE文はデータを削除するためのコマンドで、基本構文は以下の形式です。
```
DELETE FROM テーブル名;
```

例えば、以下のようなコマンドでは、「愛媛（Ehime）の大洲市（Ozu）」を削除することができます。
```
DELETE FROM city WHERE countrycode='JPN' and district='Ehime' and name='Ozu';
```

## ビュー（View）の作成

ビューとは指定したSELECT文に名前を付け保存しておく機能で、基本構文は以下の形式です。
```
CREATE VIEW ビュー名 (列名1, 列名2,...) AS SELECT文;
```

作成されたビューに対してSELECTを行うことで、あたかもテーブルからデータを取得するように利用することができます。

ビューを使うことで、以下のようなメリットがあります。
- 集計など、複雑なクエリを毎回記述しなくて済む
- 容量を使わずに実現できる
- ビューを削除しても実際のテーブルは影響を受けない

## 結合（JOIN）
結合とは、2個以上のテーブルを突き合わせてSQLを発行する方法です。

### 内部結合（INNER JOIN）とは
内部結合とは、2個のテーブルを突き合わせる条件に合致したレコードだけを取得する方法で、基本構文は以下の形式です。
```
SELECT 選択した列のリスト FROM 1つ目のテーブル名 INNER JOIN 2つ目のテーブル名 ON 結合条件;
```
例えば、以下のSELECT文では、countrycode を結合の条件にして countrylanguage テーブルからは「全ての列（*）」を、country テーブルからは「name列」を持ってきています。 
```
SELECT countrylanguage.*, country.name FROM countrylanguage INNER JOIN country ON countrylanguage.countrycode = country.code WHERE language='JPN';
```

### 外部結合（OUTER JOIN）とは
外部結合とは、2個のテーブルを突き合わせる条件に合致しなかったレコードも含めて取得する方法で、基本構文は以下の形式です。
```
SELECT 選択した列のリスト FROM 1つ目のテーブル名 LEFT OUTER JOIN 2つ目のテーブル名 ON 結合条件;
```

ここで取得されるレコードは1つ目に指定したテーブルから取得され、結合条件に合致していないレコードは該当のカラムが NULL となります。

もうひとつの外部結合に RIGHT OUTER JOIN がありますが、これはレコードを取得する基準となるテーブルが2つ目になること以外、LEFT OUTER JOIN と全く同じ挙動となります。

## 参考

https://www.shoeisha.co.jp/book/detail/9784798135168