大丈夫だよ〜、SQLだよ〜、怖くないよ〜

私事ながら25年4月をもって大学を卒業し社会人になりました。

新卒研修の中に`SQL`がありまして、ワタクシは一応経験者なのでヌルッと終えたのですが、宇宙猫みたいになってる同期もいた気がしました。
![宇宙猫の画像](https://i.pinimg.com/564x/0c/ce/46/0cce469196c70025bbd8dfef2e9cbfaa.jpg)
もちろん研修はとっても分かりやすくてサポートもしっかりしてくれてました。
でもでも〜、やっぱり〜、難しいんだよな〜。

当然です、総合職採用の人も研修に参加しているのですから。
人生初プログラミング言語が`SQL`って、人生初遊園地で富士急行くみたいな感あります。（知らんけど）
そこで、「僕的こう理解したら分かりやすいポイント」を共有したいと思います。

ディティールは端折っているので悪しからず。

# まず、SQLとは何か

`SQL`、それは`知識`です。
我々人間、生きていたら覚えておきたいものができますよね。
:arrow_down: こんな感じに。

```:知識 Lv.1
明日会社に行く
会議に参加（8:00)
部長と12時に面談
```

でも、これだとちょっと見にくいですね。
時間とやることがバラバラです。
:arrow_down: こんなふうにしてみましょう。

```:知識 Lv.2
|番号|時間|やること　|
===================
|①　|明日|会社に行く|
|②　| 8時|会議に参加|
|③　|12時|部長と面談|
```

いいですね。
情報が整理されて見やすくなりました。
誰かと共有するときも「②の時間だけど変更できる？」と明確に話すことができます。
これが人間の獲得した「表」という素晴らしい仕組みです。

そして、この「表」という仕組みはシステムの世界でも大変有効です。

システム的にタスクの時間を取得することを考えましょう。
`知識 Lv.1`から時間を取得するためには、テキスト検索などが必要になり難易度が高そうです。
一方、`知識 Lv.2`では「2列目」と表現できるので簡単そうですね。
この仕組みを積極的に活用していくために使うのが`SQL`です。

# なぜSQLなのか

> 知識を扱うのに表形式が便利だって？
> そんなことは分かってるよ！だって`Excel`使ったことあるもん！

そうです。
我々には慣れ親しんだ`Excel`という、表を扱う大変使いやすいツールがあります。
なのに、何故あれほど難解なプログラミングをせねばならないのでしょうか。

それは、`Excel`が使いやすいからです。

> 使いやすいから…、使えない…？

使いやすいというのはどういうことでしょうか。
よく分からない文字列を打ち込まないでよく、目で見てマウスで操作できるってことです。
この見て操作できるシステムを`GUI`といいます。
逆に、文字列を打ち込んで操作しないといけないシステムを`CUI`といいます。
さて、この`GUI`、重いんです。
なぜ重いのかというと、パソコンの中がこんな仕組みになっているからです。

```:これはイメージですよ！
[CUI]
                   難解な文字列の指示
人間 <--------------------------------------------> システム

[GUI]
      マウスなど視覚情報            難解な文字列の指示
人間 <----------------> 通訳マン <-----------------> システム
```

この翻訳が結構大変なんです。
`GUI`はシステムとの会話を人間が理解しやすい視覚情報に翻訳してくれているから重いんですね。

> でも、`Excel`って重くないよ？

ええ、そうなんです。
そうなんですが、会社とかで扱うデータって、それはもう膨大な量なんです。多分。
ウン十万、ウン百万、ウン千万というデータを扱います。
そうすると流石の`Excel`も音を上げます。
それに、そんなたくさんの行をドラッグしたりって大変ですよね。
そこで出てくるのが`SQL`です。
`CUI`である`SQL`は軽くて、速いのです。

もちろん、それだけじゃなくって、他のシステムから使いやすかったり、複雑な処理ができたり、整ったデータを作れたり、色々といいことがたくさんあります！

# では、どのように使うのか

`SQL`は言語ですので、`SQL`を書きます。
そしてそれを実行します。

「パパー、リモコンとって〜」
これは日本語です。
`リモコンを取る`という指示を`パパ`で実行できますね。

`SQL`も同じです。
この指示が「クエリ」というやつです。

ただし、パパが活動しているのは家の中ですが、`SQL`が活動するのはデータベースという世界になります。
データベースの世界では少し細かく指示をしないといけません。

まず、リモコンはどこにあるのでしょうか？
ここでは机の上としましょう。

```sql:リモコンデータベースへの指示
select リモコン from 机;
```

パパ（SQL）は頑張ります。
パパの返答は？ :arrow_down: 

| リモコン |
|:-:|
|テレビ|
|エアコン|
|照明|

これはまずいです。
机の上にはたくさんリモコンが置いてありました。
なんのリモコンを取って欲しいかも指示しないといけませんでしたね。

```sql:リモコンデータベースへの指示
select リモコン from 机 where リモコン = テレビ;
```

パパは再び頑張ります。

|リモコン|
|:-:|
|テレビ|

無事にテレビのリモコンが手に入りました。:raised_hands:

### 喜ぶのはまだ早い

先ほどのデータベースには問題があります。
次の場合にどうやって対応するでしょうか。
「パパー、ティッシュ取って」
「パパー、スマホも〜」

```sql:「リモコン」データベースへの指示
select ティッシュ from 机;
```

> パパ「ティッシュ…？」

そうです。
**リモコンデータベース**にはティッシュという列は存在しません。
ティッシュデータベースに聞かないといけないですね。
でも、ティッシュにスマホ、新聞も…、全部別のデータベースにしたら大変です。

> :girl: 「パパ、ティッシュが欲しいんだけど、ティッシュの情報が載っているのはどのデータベース？」
> :man: 「うーん、ティッシュデータベースだね」
> :girl: 「じゃあティッシュデータベースからボックスティッシュを取って欲しいな」
> :man: 「よし分かった、今からティッシュデータベースを開くからちょっと待っててね」
> :girl: 「パパー、鼻水垂れちゃうよぉ…」

### どうすれば良いのか

取って欲しいものを全て同じデータベースにまとめておけば便利そうですね。
ついでに、机の上のものだけじゃなくて、部屋中のものをまとめておけば更に便利そうです。
そうすると列の名前も変わりそうですね。

| 番号 | 種類 | 追加情報 | 場所 |
|:-:|:-:|:-:|:-:|
| 1 | リモコン | テレビ | 机 |
| 2 | リモコン | 照明 | 机 |
| 3 | リモコン | エアコン | 机 |
| 4 | ティッシュ | ボックス | 机 |
| 5 | ティッシュ | ポケット | カバン |
| 6 | スマホ | 娘の | ソファ |
| 7 | 新聞 | NULL | 床 |
| 8 | スマホ | パパの | 机 |

いい感じです。
こうすると、**各列が「情報の種類」を示し、各行が「もの自身」と紐つく**ことになります。
これが`リレーショナルデータベース`というシステムの基本的な構造になります。

何かを取って欲しいときには次のように言えばいいですね。

```sql:部屋のものデータベースへの指示
select * from 部屋 where 種類 = リモコン and 追加情報 = テレビ;
select * from 部屋 where 種類 = スマホ and 場所 = ソファ;
```

パパ、またまた頑張ります。
ちなみに`*`は全てという意味で、この場合は該当する行を一行分取得することになります。

| 番号 | 種類 | 追加情報 | 場所 |
|:-:|:-:|:-:|:-:|
| 1 | リモコン | テレビ | 机 |
| 6 | スマホ | 娘の | ソファ |

テレビのリモコンも、机の上のスマホも、上手に取ってもらうことができましたね！

### つまり？

つまり、`SQL`の使いやすさはデータベースの設計次第ということです。
そして、どんな指示を出すべきか、それもデータベースの設計次第です。

# 最も重要なこと

以上のことを踏まえると、`SQL`を学ぶために重要なことが見えてきます。

:::note
`SQL`とは、表として整理された情報を操作する言語です。
:::

:::note
記述する時はデータベースの構造を理解することが大切です。
:::

:::note
`SQL`の表は<INS><B>情報の種類</B>を表す「列」</INS>と、<INS><B>個々のデータ</B>である「行」</INS>で構成されます。
:::

基本的には運用中に列が変化することはありません。
ある行の3列目には「追加情報」が、違う行の3列目には「重さ」が、と言うように、同じ列に違う種類の情報が混在していたら困りますよね。
運用中に起こる変化は、行が増える、行が減る、行が書き換えられる、ということになります。

ちなみに、運用というのは部屋の例で言えば「生活」です。
そこで起きる変化は「新しくタブレットを買った」とかです。
その場合、`部屋のものデータベース`にはタブレットの行が増えることになりますね！

:::note
`SQL`の表は「**テーブル**」と呼ばれます。
:::

部屋の例ではデータベースと呼びましたが、正しくは「部屋のものテーブル」です。
`表=テーブル`です。

データベースというのは、広義では「情報を保存しておく場所」という概念であり、狭義ではリレーショナルデータベースにおける「複数のテーブルの集合」です。
後者のイメージは、「家」というデータベースがあり、その中に「リビングのものテーブル」「パパの部屋のものテーブル」「玄関のものテーブル」があるような感じです。

:::note
テーブルは、最低一つの、各行が一意となる値の列を持ちます。
:::

「各行が一意となる値の列」とはなんでしょうか？
これは`プライマリーキー`と呼ばれ、`部屋のものテーブル`では「番号」の列に相当します。

一意となる、とは「そのテーブル全ての行について重複のない」ということです。
番号が3の行といえば「机にあるエアコンのリモコン」の行しかありませんよね。
行を指定して書き換えたり削除するために必要となるので、テーブルは必ず`プライマリーキー`を持ちます。

概ね、`プライマリーキー`に使用される値は通しの番号だったり`uuid`という長い文字列だったりします。

:::note
多くの場合、一つのデータベースには複数のテーブルが存在します。
:::

> 「家」というデータベースがあり、その中に「リビングのものテーブル」「パパの部屋のものテーブル」「玄関のものテーブル」がある

テーブルを分けておくと色々と便利なことがあります。

例えば、SNSでユーザーを管理するデータベースを考えましょう。
ある`テーブルA`には「ユーザーのアカウント名」「ユーザーのアイコン」などを登録しておきます。
違う`テーブルB`に「ユーザーのパスワード」を保存しておきます。
また違う`テーブルC`に「ユーザーの投稿内容」を保存しておきます。

こうすることで、どんないいことがあるでしょうか？

`テーブルC`は色んな人が読み書きをしそうですよね。
投稿をしたり、投稿を見たり、投稿を書き換えたり…。

でも`テーブルA`はどうでしょうか？
色んな人が読み取りするのは問題ないですが、書き込みはちょっと慎重になりますよね。
やたらめったら削除されたり、アカウント名を適当に変更されたら困ります。

そしてパスワードが保存されている`テーブルB`は読まれたら困りますよね。
なんとしても秘密にしておきたいです。

これを一つのテーブルに保存しておいたら管理が大変そうですよね。
テーブルを分けることでテーブルごとに権限とかを設定できます。

エクセルで言うと、ファイルを分けておけば「これは見ていいけどこっちはダメ」みたいに管理できるよねって話です。

# よし分かった、それで、どうやって使うの？

実際の`SQL文`は`AI`に聞いたりググったりするのが早いです。

代表的なものだけ紹介します。

## 基本のき

#### 改行と二つ目以降の空白は意味を持ちません。
次の三つは同じ意味になります。

```sql
select * from hoge;
--------------------
select
*
from
hoge;
--------------------
select       * from      hoge;
```

でも、むやみやたらに改行したりするのはやめましょうね。

#### 型

プログラミングの世界では「型」というものがあります。
これは、「あらかじめ種類を決めておく」と覚えておくといいでしょう。

病院に来る患者さんの型は「人間」です。
そこに違う型の「動物」が来たら困りますよね。
あるいは、型が決まってなくて「人間」と「動物」が一緒に来ても困りますよね。

プログラムも同じです。
数字が来るだろうと処理を進めていて文字が来たら困るのです。

だから、あらかじめ型というデータの種類を決めておいて、処理が円滑に進むよう工夫しているのです。

## SELECT

先ほどから何度も出てきていますね。
情報を取ってきて〜ってやつです。

```sql
select row_name from table_name;
```

`取得したい列名`と`取得したいテーブル名`を指定します。

:::note info
列は英語で「Column」、行は英語で「Row」です。
列と行は`つくり`で覚えるんでしたね。
では英語は？
開いているところで覚えます。
![row_col.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684034/e9eb553a-2cb8-46c5-9398-428da0e96344.png)
先人の知恵とは偉大ですね！
:::

### FROM

どんなクエリでもほぼ必ず使う`FROM`ですが、本棚と机を想像するといいと思います。

![FROMのイメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684034/9cd8f284-0d68-4327-bd68-c1ca0bd4975e.png)

いろんなテーブルが入っているデータベースから、これから作業するテーブルを指定するコマンドになります。
本棚から、本（テーブル）を取り出して、机に広げてね！という指示になります。

### SELECT

次は広げた本（テーブル）から任意の列を取り出していきます。

```sql
select 住所 from table_name;
```

![SELECTのイメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684034/7d9b491b-91d3-48af-8712-f8811ceca816.png)

これだとたくさんの行が返ってきてしまいます。
なので`LIMIT`を使ったりします。

急に「リモコン53万個も取って！」とか言われたらパパも困っちゃいますからね！

### ORDER BY

一番年齢が若い人の住所が欲しい時とかには並べ替えをします。

```sql
select 住所 from table_name order by 年齢 asc;
```

:::note info
由来は英単語です。
**ASC**ending : 上昇
**DESC**ending : 下降

昇順は**進むにつれ昇っていく**ので、一番最初は一番小さくなりますね。
`A->Z`も昇順です。
:::

### WHERE

田中さんのデータが見たい！という時はどうすればいいでしょうか。

```sql
select * from table_name where '名前' = '田中';
```

これで名前列の値が「田中」の行が全て選択できます。
等号不等号いろいろな比較演算子で検索できます。

## GROUP BY

任意の列が同じ値の行をグループ化してくれます。

| 番号 | 種類 | 追加情報 | 場所 |
|:-:|:-:|:-:|:-:|
| 1 | リモコン | テレビ | 机 |
| 2 | リモコン | 照明 | 机 |
| 3 | リモコン | エアコン | 机 |
| 4 | ティッシュ | ボックス | 机 |
| 5 | ティッシュ | ポケット | カバン |
| 6 | スマホ | 娘の | ソファ |
| 7 | 新聞 | NULL | 床 |
| 8 | スマホ | パパの | 机 |

例えば、上のテーブルがあるときに「物がおいてある場所を全部知りたい」みたいな時。

```sql
select 場所 from 部屋 group by 場所;
```

|場所|
|:-:|
|机|
|カバン|
|ソファ|
|床|

注意点は、`GROUP BY`を使ったら<B>「グループ化した列」と「関数の結果」しか取得できない</B>ということです。
なぜでしょうか。

`GROUP BY 場所`の後を考えてみましょう。
場所でグループ化するので次のようになりますね。

| 番号 | 種類 | 追加情報 | 場所 |
|:-:|:-:|:-:|:-:|
| 1,2,3,<br>4,8| リモコン,リモコン,<br>リモコン,ティッシュ,<br>スマホ | テレビ, 照明, エアコン, ボックス, パパの | 机 |
| 5 | ティッシュ | ポケット | カバン |
| 6 | スマホ | 娘の | ソファ |
| 7 | 新聞 | NULL | 床 |

当然ですが`GROUP BY`をすると、グループ化に使った列以外は、複数の行の値がごちゃ混ぜになってしまうのです。
こうなると、`机行`の`番号`や`種類`、`追加情報`の値は意味をなさなくなっていますね。
パパも「追加情報は`テレビ, 照明, エアコン, ボックス, パパの`だよ！」って言われても困ってしまいます。

```sql
--これはエラーになる
select 追加情報 from 家 group by 場所;
```

では関数はどうでしょうか。
例えば`COUNT関数`です。
「パパ、`追加情報`の数は5個だよ！」
これは良さそうですね。

```sql
--これはOK！
select 場所, count(追加情報) from 家 group by 場所;
```

# まとめ

元気があれば他の句とか続きを書きます。:sweat:

プログラミングの心構えは「エラーは先生、友達」です。
エラーをよく読むことはとても大切です。

そして、仕組みの裏側を知れるときっと成長すると思います。
なんでこれを使うのか、なんでダメなのか、そういうことを考える姿勢を持てるといいですね。
僕も持ち続けたいです。

致命的に間違っているところがあれば教えてください。:bow:
いいねしてもらうと僕が喜びます。

拙い文章ですが最後まで読んでいただいてありがとうございました！