最近、社内でエンジニア以外の方へSQLを教える機会があり、そこだけの話にするのはもったいないと思ったのでqiitaにまとめてみました。
はじめに
データドリブンと言われるようになって久しい今日この頃、営業や企画など非エンジニアの方もSQLを駆使してデータを取得している場面をよく目にするようになりました。
ただ、SQLとかデータベースとかハードルが高いよ!と感じている方も多いと思います。
しかしデータを参照するためのSQLだけであればすごく簡単に習得できるので是非チャレンジしてみてください。
なお、この記事ではデータ参照のみを扱います。また参照の中でも使用頻度が高いと思われるもののみ扱います
前提条件
- SQLを実行してデータを取得できる環境があり、アクセスできること
- そもそもデータベースを使っていない場合は対象外です
- データドリブンを掲げているのであれば参照専用の環境はあるはず
- SQLを毎回書いてデータを取得するのはアドホックなデータを取得したい時です
- 定型データの抽出はミスなく簡単に取得できるようにシステム化してもらいましょう
データについて
データは「テーブル」と呼ばれる箱に入っています。
テーブルは「カラム」と呼ばれるデータ項目を持っています。
Excelなどの表を想像するとよいかもしれません。
テーブルの具体例
文章だけではわかりづらいので具体例を挙げます。
ユーザー情報、試験情報、ユーザーが受験した試験情報の3つのテーブルを使います。
ユーザー情報を持っているテーブル「users」
ユーザー情報は「id(一意に識別するための番号)」、「name」、「email」を持っているものとする
id | name | |
---|---|---|
1 | 伊藤一郎 | ito1@example.com |
2 | 伊藤次郎 | ito2@example.com |
3 | 鈴木太郎 | suzuki@example.com |
4 | 佐藤花子 | sato@example.com |
試験情報を持っているテーブル「exams」
試験情報は「id(一意に識別するための番号)」、「name」を持っているものとする
id | name |
---|---|
1 | 国語 |
2 | 数学 |
3 | 物理 |
4 | 化学 |
ユーザーが受験した試験情報を持っているテーブル「user_exams」
ユーザーが受験した試験情報は「exam_id(受験した試験のid)」、「user_id(受験したユーザーのid)」、「point」を持っているものとする
exam_id | user_id | point |
---|---|---|
1 | 1 | 100 |
1 | 2 | 90 |
1 | 3 | 65 |
1 | 4 | 70 |
2 | 1 | 100 |
2 | 2 | 60 |
2 | 3 | 95 |
2 | 4 | 80 |
3 | 1 | 100 |
3 | 3 | 60 |
4 | 1 | 100 |
4 | 2 | 55 |
4 | 4 | 80 |
このテーブルは急に数字だらけになってしまいわかりづらいと思うので、このテーブルから読み取れることをいくつか列挙しておきます。
下記のことがテーブルから読み取れることを確認してください。
- 国語、数学の試験は4人全員が受けている
- 物理は伊藤一郎と鈴木太郎の2人が受けている
- 伊藤一郎は4科目受けており、全部100点
データ抽出のSQLについて
ここからデータ抽出のSQLについて書いていきます。
データ抽出SQLの基本形
1テーブルからデータを取得するSQLは下記の構文で記載できます。
select
[参照したいカラム1, 参照したいカラム2, ...]
from
[テーブル名]
where
[抽出条件]
[参照したいカラム]には、参照したいデータのカラム名記載します。
複数ある場合はカンマ区切りで書きます。
[テーブル名]には参照したいカラムを持っているテーブル名を記載します。
[抽出条件]には取得したいデータの条件を記載します。抽出条件は具体例を説明する時に一緒に説明します。
これまた具体例がないとわかりづらいと思うので具体例を挙げます。
ユーザー情報を全部取得
select
id, name, email
from
users
全件取得の場合は抽出条件は省略できるのでwhere
は書いていません。
- 取得結果
id | name | |
---|---|---|
1 | 伊藤一郎 | ito1@example.com |
2 | 伊藤次郎 | ito2@example.com |
3 | 鈴木太郎 | suzuki@example.com |
4 | 佐藤花子 | sato@example.com |
今回は明示的にカラムを指定しましたが、fromに指定したテーブルの全カラムが欲しい場合は*
で指定することもできます。
select
*
from
users
こちらでも1つ前のSQLと同じ結果が得られます。
逆にemailとnameだけ欲しいという場合は下記のように書きます。
select
email, name
from
users
- 取得結果
name | |
---|---|
ito1@example.com | 伊藤一郎 |
ito2@example.com | 伊藤次郎 |
suzuki@example.com | 鈴木太郎 |
sato@example.com | 佐藤花子 |
※指定したカラムの順序も結果に反映されます。
特定のユーザー情報を取得
鈴木一郎のユーザー情報を取得する場合
select
id, name, email
from
users
where
name = '伊藤一郎'
このように任意のカラムが特定の値のデータが欲しい場合はwhere
に[カラム名] = [値]
で指定できます。
今回は鈴木一郎の情報だけ必要なので、where
にname = '鈴木一郎'
と書いています。
ちなみに値は'
で囲ってください。
- 取得結果
id | name | |
---|---|---|
1 | 伊藤一郎 | ito1@example.com |
特定のユーザー情報を取得(複数)
先ほどの例では値を1つ指定していましたが、複数指定することもできます。
伊藤一郎と鈴木太郎のユーザー情報を取得する場合
select
id, name, email
from
users
where
name in ('伊藤一郎', '鈴木太郎')
複数指定する場合は[カラム名] in ([値1], [値2], ...)
で指定できます。
inの中のいずれかに一致するデータを取得できます。
- 取得結果
name | |
---|---|
ito1@example.com | 伊藤一郎 |
suzuki@example.com | 鈴木太郎 |
部分一致しているユーザー情報を取得する
伊藤という苗字のユーザー情報を取得する場合
select
id, name, email
from
users
where
name like '伊藤%'
[カラム名] like [値]
で部分一致で検索することができます。
likeを使用すると、値の中に%
(ワイルドカード)を使用することができるようになります。
例の場合は最後に%
をつけているので'伊藤'で始まるユーザー情報が取得できます。
また最後が'一郎'で終わるユーザー情報を検索する場合は%一郎
のように前に%
をつけることで検索できます。
また'藤'という漢字を含むユーザーを検索する場合は%藤%
のように前後に%
をつけることで検索できます。
※※※注意※※※
likeを使った部分一致検索はとてもパフォーマンスが悪いためデータ量が多い場合、データ抽出にかなりの時間がかかる可能性があります。
(likeに限らずですが)そういった事象に遭遇した時はSQLに詳しい方に相談してください。
- 取得結果
name | |
---|---|
ito1@example.com | 伊藤一郎 |
ito2@example.com | 伊藤次郎 |
複数カラムの条件指定
user_examsから国語(exam_id=1)で80点以上のユーザーIDを取得する場合
select
user_id, point
from
user_exams
where
exam_id = 1
and point >= 80
条件に複数のカラムを指定する場合はand
を使います。and
を使うことで全ての条件を満たすデータを取得できます。
数値データの場合は'
で囲む必要はありません。
値の比較に不等号を使うこともできます。具体例は下記の通り。
where | 抽出できるデータ |
---|---|
point = 100 | 100点のデータ |
point >= 50 | 50点以上のデータ |
point > 50 | 50点より高いデータ |
point <= 50 | 50点以下のデータ |
point < 50 | 50点より低いデータ |
point <> 100 | 100点以外のデータ |
- 取得結果
user_id | point |
---|---|
1 | 100 |
2 | 90 |
ユーザーID1,2のユーザーが国語で80点以上をとったということがわかりました。
ただ、よくあるユースケースではユーザーIDだけではなく名前も欲しくなりますよね?
追加でusersからid in (1, 2)
と検索することで取得できますが、人数が多いと大変なのでもっと手軽に取得したいですよね。
ということで次は複数のテーブルからデータを取得する方法を説明します。
複数テーブルからデータ抽出
複数のテーブルを結合することで各テーブルの情報をまとめて取得することができます。
テーブル結合の構文
from
のところで結合したいテーブルをinner join [テーブル名] on [結合条件]
で指定します。
select
[参照したいカラム1, 参照したいカラム2, ...]
from
[テーブル名]
inner join [結合テーブル1] on [結合条件]
inner join [結合テーブル2] on [結合条件]
...(結合したいテーブルの数だけ記述)
where
[抽出条件]
結合条件にはレコードを結合する条件を書きます。
例えばusersとuser_examsでは、users.idとuser_exams.user_idが同じユーザーのことを示しているので下記のように指定します。
from user_exams
inner join users on users.id = user_exams.user_id
上記のように結合させると結合後のテーブルは次のようなイメージになります。
user_exams.exam_id | user_exams.user_id | user_exams.point | users.id | users.name | users.email |
---|---|---|---|---|---|
1 | 1 | 100 | 1 | 伊藤一郎 | ito1@example.com |
1 | 2 | 90 | 2 | 伊藤次郎 | ito2@example.com |
1 | 3 | 65 | 3 | 鈴木太郎 | suzuki@example.com |
1 | 4 | 70 | 4 | 佐藤花子 | sato@example.com |
2 | 1 | 100 | 1 | 伊藤一郎 | ito1@example.com |
2 | 2 | 60 | 2 | 伊藤次郎 | ito2@example.com |
2 | 3 | 95 | 3 | 鈴木太郎 | suzuki@example.com |
2 | 4 | 80 | 4 | 佐藤花子 | sato@example.com |
3 | 1 | 100 | 1 | 伊藤一郎 | ito1@example.com |
3 | 3 | 60 | 3 | 鈴木太郎 | suzuki@example.com |
4 | 1 | 100 | 1 | 伊藤一郎 | ito1@example.com |
4 | 2 | 55 | 2 | 伊藤次郎 | ito2@example.com |
4 | 4 | 80 | 4 | 佐藤花子 | sato@example.com |
user_examsに結合条件であるuser_exams.user_idとusers.idが一致するレコードがくっつくイメージです。
users, user_exams, examsの結合
先ほどの例と同じでuser_examsから国語(exam_id=1)で80点以上のユーザーIDを取得する場合を考えます。
今回はユーザー名が知りたいのでusersテーブルを結合します。ついでに試験名も取得するためにexamsも結合します。
select
users.id, users.name, user_exams.point, exams.name
from
user_exams
inner join users on users.id = user_exams.user_id
inner noin exams on user_exams.exam_id = exams.id
where
user_exams.exam_id = 1
and user_exams.point >= 80
1テーブルの時と違い、カラム名に[テーブル名].
をつけています。
1テーブルの場合はテーブル名を指定しなくてもどのテーブルのカラムかわかるので省略できるのですが、複数テーブルある場合は同名のカラムがある可能性があるのでテーブル名を指定します。
ということなので、どのテーブルとも被っていないカラムはテーブル名は省略可能です。ただ、最初のうちはわかりやすさのためにもテーブル名は指定するものと覚えても良いかもしれません。
抽出結果は下記の通り
users.id | users.name | user_exams.point | exams.name |
---|---|---|---|
1 | 伊藤一郎 | 100 | 国語 |
2 | 伊藤次郎 | 90 | 国語 |
並び順
抽出するデータの並び順を指定することができます。
下記のようにorder by
で指定します。
select
[参照したいカラム1, 参照したいカラム2, ...]
from
[テーブル名]
where
[抽出条件]
order by
[ソートカラム] [ソート条件], [ソートカラム2] [ソート条件],...
例えばuser_examsで点数の高い順に並べたい場合は下記のように書きます。点数が同点の場合はuser_idの昇順にします。
ソートカラムに指定した1つ目のカラムで並び替えますが、もし同じ値の場合は2つ名のソートカラムでさらに並び替えます。もしそこも同じ値であれば3つ目のソートカラム、いうように同値がある限り次のソートカラムを参照して並べようとします。
もし同じ値があるのに次のソートカラムが指定されていない場合は取得順は不定になります。
select
exams_id, user_id, point
from
user_exams
order by
point desc, user_id asc
ソート条件に指定しているdesc
は降順を指定しています。asc
は昇順です。
このSQLを実行すると下記のように出力されます。
exam_id | user_id | point |
---|---|---|
1 | 1 | 100 |
2 | 1 | 100 |
3 | 1 | 100 |
4 | 1 | 100 |
2 | 3 | 95 |
1 | 2 | 90 |
2 | 4 | 80 |
4 | 4 | 80 |
1 | 4 | 70 |
1 | 3 | 65 |
2 | 2 | 60 |
3 | 3 | 60 |
4 | 2 | 55 |
point=100のデータは全てのuser_id=1であり、orderで指定されたカラムだけでは順番が確定できないので、順番は不定になります。
もし順番を確定させるのであれば、ソートカラム3にexam_idを指定するなどして順番が確定するようにします。
集計
SQLではデータ数などの集計情報を取得することができます。
集計を詳しく説明するととても複雑なのでここでは単純なデータ数の取得だけ触れることにします。興味がある方は別途調べてみてください。
データ数をカウントする
データ数をカウントします。例えばuser_examsで80以上のデータ数をカウントする場合は下記のSQLを書きます。
select
count(*)
from
user_exams
where
point >+ 80
結果は下記の通り
count(*) |
---|
8 |
最後に
なんやかんやで長くなってしまいましたが、単純に抽出するだけのSQLであれば比較的簡単に理解できたと思います。
できる限り具体例を交えて説明しましたが、習得するには実践あるのみだと思いますのでガンガンSQLを使っていってください。
簡単に書いたつもりではいるのですが、SQLを知っている人(私)が書いているので知らない人には意味がわかりづらい表現もあると思います。
そういうところはぜひコメントなどしていただければと思います。
できる限り改善したいと思います!
この記事では基本的なことしか書いていません。SQLでデータ抽出をよくやるようになると書いてあることだけではできない様々な抽出をやりたくなると思います。
そうなったときにはすでにSQL初心者は脱していると思うので、次のステージへステップアップしていってください!