サザエさんと学ぶSQL構文(参照クエリチートシート)

# Introduction

## きっかけ
データベースの勉強をしようということで、入門書を読みました。
そこでデータベースの入門書を元に、自分への備忘録としてまとめます。
しかしただ入門書と同じ実験データで話しても面白くないということで、サザエさんのキャラクターを用いて解説いたします。[^1]

## 要約
本稿では、SQLの基本的な参照コマンドと実行結果を画像を用いて紹介します。

<話すこと>
・SQLデータベースの操作(参照)
・SQLのデータベースの作り方
・ビューを作成する方法とメリット
に関する構文の紹介
磯野家、フグ田家の家族構成

<話さないこと>[^2]
・環境構築に関すること
・SQLデータベースの操作(集約、整列)
・サブクエリの用法
・外部結合、内部結合
・かもめ小学校のこと、伊佐坂先生についてなど


## 自己紹介
![smile.jpg](https://qiita-image-store.s3.amazonaws.com/0/262742/38a82ae5-98e6-8d78-b461-3d14024af15d.jpeg)

[自己紹介ページ](https://qiita.com/Senple/items/b47374e68e4d8d26d0cb)

```
環境情報
macOS Catalina ver:10.15.3
SQL Ver 8.0.19 for osx10.15 on x86_64 (Homebrew)
```

### 対象者
・SQLの初心者の方
・1を聞いて10を理解できるエンジニア
・mysql系データベースを使いたい方
・**Macユーザー**の人
・サザエさんを過去見たことがある方。

### 非対象者
・SQLが超お得意な人
・説明下手な筆者を攻撃しようとするエンジニア
・mysql以外のDBMS系データベースを使いたい方[^3]
・**Windowsユーザー**の人 [^4]
・サザエさんのファン


# Let's Start

## 1. データベースの操作方法

今回は、以下のデータベースを操作していきます。

<img width="705" alt="qiita_select_tables.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/d52f8bb6-3fdc-8925-7854-346391664a77.png">

### Case1:表から列名を指定して取得します。

実際の想定例・・・
サザエさんには、どんな名前のキャラがいるのか忘れた時。


```sql
SELECT name FROM Family;
```
Family表のname列を取得します。

<img width="248" alt="qiita_select_name_from_table.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/cc176776-35c1-c7ee-da61-f1fe9cba3e5b.png">


### Case2:表から複数の列名を指定して取得します。

実際の想定例・・・
サザエさんに登場するキャラの年齢を知りたい時。


```sql
SELECT name, age FROM Family;
```
Family表のname列とage列を取得します。

<img width="274" alt="qiita_select_name_age_from_table.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/db46f680-c322-6b6a-5c46-4bf9ff590f00.png">


>Error:
複数選択するときの注意として、列名全てにコンマを付すと、エラーを吐きます。
エラー例
SELECT name, age, FROM Family;
僕も何度も苦しみました。気をつけてください！

<img width="634" alt="qiita_select_names_error.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/19cde0fd-911c-8cab-684b-9db5f877c32e.png">


### Case3:表から列名を指定して重複を除いて取得します。

実際の想定例・・・
サザエさんに登場するキャラってどんな性別があるっけ？と、気になって気になって夜も眠れないとき。


```sql
SELECT DISTINCT gender FROM Family;
```
Family表のgender列を取得します。

<img width="305" alt="qiita_select_distinct_gender.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/040025be-4beb-8c32-26aa-b4f5c110c61f.png">


### Case4:表から複数の列から、重複を除いて取得します。

実際の想定例・・・
サザエさんに登場するキャラが、それぞれの性別で昼間どんなことしてるのか知りたくなったとき。


```sql
SELECT DISTINCT gender, category FROM Family;
```
Family表から重複を除いてgender列とcategory列を取得します。

<img width="379" alt="qiita_select_distinct_gender_category.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/ed94887a-fa5b-fc7c-a1ce-50aada957316.png">


### Case5:表から条件に該当するデータを検索して、取得します。

実際の想定例・・・
サザエさんに登場する女性キャラを、知りたくなったとき。

```sql
SELECT name, gender FROM Family WHERE gender = '女';
```
Family表からgender列が「女」という条件のname列とgender列を取得します。

<img width="421" alt="qiita_select_name_gender_where_female.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/94428a99-04c9-192d-9e6c-5b3d80638d8e.png">


### Case6:表からNULLが含まれるデータを検索して、取得します。

実際の想定例・・・
サザエさんに登場するキャラのなかで、血液型がわからない人は誰なのか気になったとき。[^5]

```sql
SELECT name, blood FROM Family WHERE blood IS NULL;
```

Family表からblood列がNULLであるname列とblood列を取得します。

<img width="421" alt="qiita_select_name_blood_where_is_null.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/a809ed29-406d-0182-a2df-c118b9dac28d.png">

>Column:
NULL以外のものが知りたい時は、
SELECT name, blood FROM Family WHERE blood IS NOT NULL;
をご利用ください。


### Case7:表から任意の値からの大小を指定したデータを検索して、取得します。

実際の想定例・・・
サザエさんに登場するキャラのなかで、20才以上は誰なのか気になったとき。

```sql
SELECT name, age FROM Family WHERE age >= 20;
```

Family表からage列が20以上であるname列とage列を取得します。

<img width="369" alt="qiita_select_name_age_where_20over.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/0e5f994d-955b-141e-8840-6f75924adbe4.png">

>Error:
20歳以上を記述するときに、「>=」じゃなくて、「=>」とすると、エラーを出力します。
SELECT name, age FROM Family WHERE age => 20;

<img width="636" alt="qiita_select_name_age_error.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/da87e479-39c0-b3a7-f9bd-cb1ec9389456.png">

参考：
他の比較演算子の場合は以下のように記述します。


等しいとき「=」 (20歳であるとき)

```sql
SELECT name, age FROM Family WHERE age = 20;
```

等しくない「<>」 (20歳でないとき)

```sql
SELECT name, age FROM Family WHERE age <> 20;
```

より大きい「>」 (20歳より大きいとき)

```sql
SELECT name, age FROM Family WHERE age > 20;
```

以上「>=」 (20歳以上であるとき)

```sql
SELECT name, age FROM Family WHERE age >= 20;
```

より小さい「<」 (20歳より小さいとき)

```sql
SELECT name, age FROM Family WHERE age < 20;
```

以下「<=」 (20歳以下であるとき)

```sql
SELECT name, age FROM Family WHERE age <= 20;
```

### Case8:表から複数の条件を指定してデータを検索して、取得します。

実際の想定例・・・
サザエさんに登場するキャラのなかで、年齢が３０歳に満たない男性を知りたくなったとき。

```sql
SELECT name, gender, age FROM Family WHERE gender = '男' AND age < 30;
```

Family表からgender列が「男」で、かつage列「30未満」であるname列とgender列とage列を取得します。

<img width="564" alt="qiita_select_name_age_gender_where_age_30_gender_male.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/62ffee26-255f-950c-85d5-94d7223a903c.png">

参考：
ほかの論理演算子の場合は以下のようになります。

「または」(男性もしくは、B型でない)

```sql
SELECT name, gender, blood FROM Family WHERE gender = '男' OR blood <> 'B型';
```

「否定」(男性でない)

```sql
SELECT name, gender FROM Family WHERE NOT gender = '男';
```

### Case9:Betweenで範囲を指定します。

実際の想定例・・・
サザエさんに登場するキャラのなかで、1900年から1910年の間に生まれたのは誰なのか気になったとき。

```sql
SELECT name, birthday FROM Family WHERE birthday BETWEEN '1900-01-01' AND '1910-12-31';
```

Family表からbirthday列が「1900-01-01」から「1910-12-31」の間にあるname列とbirthday列を取得します。

もちろん以下の記法でも大丈夫です。

```sql
SELECT name, birthday FROM Family WHERE birthday >= '1900-01-01' AND birthday <= '1910-12-31';
```
<img width="726" alt="qiita_select_name_birthday_between.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/5169b487-28f2-f95c-1dff-db1158170646.png">


### Case10:複数の論理演算子を使用した場合の優先順位を確認します。[^6]

実際の想定例・・・
サザエさんに登場するキャラのなかで、血液型が「不明」もしくは「A型」の女性が誰なのか、クイズで答える必要があるとき。

```sql
SELECT name, gender, blood FROM Family WHERE (blood IS NULL OR blood = 'A型' ) AND gender = '女';
```

Family表からblood列が「空白」もしくは「A型」で、かつgender列が「女」という条件のname列とgender列とblood列を取得します。


<img width="374" alt="qiita_select_name_gender_blood_where_AND_OR.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/8d449790-a9ad-4f24-abda-00e671f6a096.png">

### Case11:指定した文字列を含むデータを取得します。

実際の想定例・・・
サザエさんに登場するキャラのなかで、名前に「野」がつく人を知りたくなったとき。

```sql
SELECT name FROM Family WHERE name LIKE '%野%';
```

Family表からname列に「野」が含まれるname列を取得します。

<img width="415" alt="qiita_select_name_like_wildcard.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/5f0e6d18-6c31-17ce-0879-5271ab2cd3a8.png">


参考：
「%」は、ワイルドカードと呼ばれ「任意のデータの代用」をできます。%は文字数が不明なときに、利用できます。
ワイルドカードは、他に「_」があります。文字数がわからない時は、「%」を、文字数がわかる時は、「_」を使い分けることで、効率よくデータを取得できます。
例えば「磯野波平」を取得したい時は、4文字ということが分かっていれば、「%」よりも「_」を使う方が効率よく検索することができます。

```sql
SELECT name FROM Family WHERE name LIKE '_野__';
```

## 2. もっと細かく検索したい人向け！
より細かく検索ができるように、ビューという方法があります。

### Case12:特定の条件で、表を分割して名前をつける。

実際の想定例・・・
サザエさんに登場するキャラを、磯野家という家族単位で管理したい。

```sql
CREATE VIEW Isonoke AS SELECT * FROM Family WHERE name LIKE '磯野%';
```

Family表からname列に「磯野」が含まれるという条件で、全ての列を取得して、「Isonoke」という名前をつけます。

<img width="678" alt="qiita_create_isonoke.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/da352a73-0790-4b44-f64d-9279d9cb4023.png">

SazaesanというDBのなかに、「Family」というテーブルと「isonoke」というビューが作成されました。ビューは、大文字小文字を区別していないので、「Isonoke」で登録しても「isonoke」として登録されています。
ビューを作成することで、「磯野家」のなかで、検索するときには、いちいちWHERE句で条件を指定しなくても良い点があります。

ちなみに新規のテーブルを作らず、わざわざビューを使うメリットは、元々のFamilyのデータで変更があると、ビュー側でも変更されるからです。

もちろんフグ田家も作成できますよ！


## 3. データベースを作る方法
自らDBを作ることになることは、あまりないと思うので、DBの作り方は、簡単に紹介します。
需要があれば加筆修正いたします。

```sql
CREATE DATABASE Sazaesan;
SHOW DATABASES;
USE Sazaesan;
```

CREATE DATABASEで、データベースを作成します。
今回はSazaesanとします。
SHOW DATABASEで、現在どんなデータベースがあるのかを確認できます。
USE でどのデータベースを使うのかを指定します。
実際のデータベースを触る時は、基本的にUSEされた後の状態で使用することが多いと思います。

>Column:
sqlは、アルファベットの大文字と小文字を区別しません。
なので、create database sazaesanもCREATE DATABASE SAZAESANも全て同じ命令ですが、入門書に書いてあった通りSQL命令を大文字表記、データベースや表の名前は先頭大文字表記、列名などは全て小文字表記として記述しています。

表を作って、データを入力します。

```sql
SHOW TABLES;
CREATE TABLE Family(
family_id CHAR(4) NOT NULL,
name VARCHAR(10) NOT NULL,
gender CHAR(1) NOT NULL,
birthday DATE NOT NULL,
category VARCHAR(10) NOT NULL,
category_id CHAR(4) NOT NULL,
age INT,
blood VARCHAR(3),
PRIMARY KEY(family_id));
```

>Column:
それぞれの列名と列のデータ型、空白を許すか否かを定義します。
データ型は、
整数型(INT)・・・小数点以下がない数値
実数型(DOUBLE)・・・小数点以下がある数値
固定長文字列型(CHAR)・・・固定された文字数の文字列
可変長文字列型(VARCHAR)・・・任意の文字数の文字列
日付型(DATE)・・・YYYY-MM-DD形式の日付
の５種類あります。
今回のテーブルでは、実数型を除く４種類を用いました。


Family表にデータを登録します。

```SQL
INSERT INTO Family VALUES('F001', '磯野波平','男','1895-09-14', 'office','C001',54, NULL);
INSERT INTO Family VALUES('F002', '磯野舟','女','1901-01-01', 'house','C002',48, NULL);
INSERT INTO Family VALUES('F003', 'フグ田サザエ', '女', '1922-11-22', 'house', 'C002', 27, 'B型');
INSERT INTO Family VALUES('F004', '磯野カツオ', '男', '1938-01-01', 'school', 'C003', 11, 'B型');
INSERT INTO Family VALUES('F005', '磯野わかめ', '女', '1942-01-01', 'school', 'C003', 7, 'A型');
INSERT INTO Family VALUES('F006', 'フグ田マスオ', '男', '1917-01-01', 'office', 'C001', 32, 'B型');
INSERT INTO Family VALUES('F007', 'フグ田タラオ', '男', '1946-01-01', 'house', 'C002', 3, NULL);
```

>参考：
INSERT INTO テーブル名 VALUES();
今回の記事では説明していない、データをテーブルに追加するコマンドです。Family表には７つのデータを追加しています。




作成できたら、確認してみます。

```SQL
SELECT * FROM Family;
```

<img width="705" alt="qiita_select_tables.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262742/d52f8bb6-3fdc-8925-7854-346391664a77.png">


アスタリスクは「指定しない」という意味です。
列名を指定すれば、その列だけを取得することも可能です。



# まとめ
サザエさんの年齢と誕生日があまりにも古くて、改めて国民的アニメの長寿さに感動いたしました。さらに驚くべきことに、サザエさんとたらちゃんは未だに一度も声優が変わっていないそうです。この記事を期にというわけでもありませんが、サザエさんをまた見てみようと思いました。~~SQL関係ない~~


# 付録(Appendix)

## 情報元
[参考にした書籍](
https://www.amazon.co.jp/%E3%81%84%E3%81%A1%E3%81%B0%E3%82%93%E3%82%84%E3%81%95%E3%81%97%E3%81%84-SQL-%E5%85%A5%E9%96%80%E6%95%99%E5%AE%A4-%E7%9F%A2%E6%B2%A2-%E4%B9%85%E9%9B%84-ebook/dp/B07S5KVWCF)
https://ja.wikipedia.org/wiki/%E3%82%B5%E3%82%B6%E3%82%A8%E3%81%95%E3%82%93%E3%81%AE%E7%99%BB%E5%A0%B4%E4%BA%BA%E7%89%A9

[^1]: サザエさん一家に関してはwikipediaをはじめとしたネットメディアで調べた情報から構成しています。完全性も正確性も保証していないため、あくまでサンプルデータとしてご認識いただきたい。
[^2]: 需要があれば、こちらの項目も書いていこうかなと思ったり思わなかったり・・・。
[^3]: SQLの文法は同じだが、SHOW DATABASES;などの部分は異なる。実際にSQLのコマンドは、ほとんど同じだがあくまで「ほとんど同じ」なので、違う部分でエラー処理に悩んだ自分の経験からそもそも対象外としている。
[^4]: 別にMacとWindowsの違いが、SQLに影響を及ぼすとは考えていないが、SQLのインストール系の話を飛ばしているため。
[^5]: 本当にどうしても気になる時は、データベースなんかよりもGoogle検索をするなり「Hey Siri!」といって聞く方が確実であるが、そんなことは野暮だ。
[^6]: 括弧をつけなくてもエラーが出るわけではないが、算術演算子(和算、減算、乗算、徐算)に優先順位があるように、論理演算子にも優先順位がある。「NOT > AND > OR」の順番で優先順位が高くなる。「NOT」の方が、「AND」よりも優先され、「AND」の方が、「OR」よりも優先される。予期しないエラーを出さないために、括弧で明示的に順序を決めておくほうが、スマートだ。