リレーショナルデータベースマネジメントシステム(RDBMS)
dataを表形式で管理→SQLでデータの登録・検索・更新・削除
- Oracle Datebase
- MySQL
- Postgresql
- SQLite
データベースの種類
- リレーショナルデータベース:
- 階層型データベース
- ネットワーク型データベース
テーブル
テーブル:ある一定のまとまりのある、表形式のデータ群
カラム:縦方向、列のデータこと
レコード(ロウ):横方向、行のデータこと
フィールド:レコードを構成する1つ1つの要素。Excelでいうセル
カラム・レコード・フィールドの関係性は、複数のレコードの同じフィールドを集めたものがカラム

SQL構文
SELECT
何のデータをどのテーブルから取り出すのか?を考えると良い。
SELECT カラム名 FROM テーブル名;
- データを複数抽出
SELECT ID, user, post FROM post_table のように『,区切り』で複数抽出できる - カラム名を変更する
SELECT ID, user as ユーザー名 FROM post_table のように『as』を使用すると変更して抽出できる - 全てのデータを抽出
SELECT * FROM post_table のようにカラム名を『*』に変更すると全てのデータを抽出することができる
WHERE
特定の条件でデータを抽出する場合に使用
SELECT カラム名 FROM テーブル名 WHERE 条件式;
列指定はカラム名、行指定は条件式と覚えると良い
条件式には、イコールや大なり、小なり、否定などの式が入る
SELECT * FROM post_table WHERE user = taro;
上記SQL構文は、post_tableからuserがtaroのデータを全ての列で取得するとなる。
ORDER BY
抽出対象のデータの並び替え(昇順、降順)をするために使用できる。
SELECT カラム名 FROM テーブル名 ORDER BY 並べ替え条件式;
SELECT * FROM post_table ORDER BY created_at ASC;
上記SQL構文は、post_tableからすべてのカラムをcreated_atの昇順に取得するとなる。
昇順は、ASC(ASCはORDER BYのデフォルトが昇順なので省略できる)
降順は、DESC
-
複数の条件式を指定できる
SELECT * FROM post_table ORDER BY created_at, user_id DESC;
のように『,区切り』で指定できるが、先に書いたカラム名(ここではcreated_at)が優先される -
WHEREとの組み合わせ
SELECT * FROM post_table WHERE user = taro ORDER BY created_at, user_id DESC;
のようにWHEREと組み合わせることも可能。
構文の書き方で注意してほしいのは、ORDER BYは、FROMとWHEREのあとに書く。
ORDER BYは最後に書くと覚える。
GROUP BY
データをルールにしたがってグルーピングするもの。
SELECTにGROUP BYを付けることで、グルーピングしたいカラムをもとに、集約関数を使って合計や平均、最小値や最大値、カウントなどが計算できるようになる。
SELECT
グルーピングをするカラム,集約関数(集計対象カラム)
FROM
テーブル名
WHERE
条件式
GROUP BY
グルーピングをするカラム
ORDER BY
並べ替え条件式;
SELECT 商品分類,sum(売上金額) FROM product_table GROUP BY 売上金額;
product_tableから商品分類ごとに売上金額を合計したデータを商品分類と一緒に抽出する。という意味になる。
-
ORDER BYとの組み合わせ
SELECT 商品名,sum(売上金額) FROM product_table GROUP BY 商品名 ORDER BY sum(売上金額);
product_tableから商品分類ごとに売上金額を合計したデータを商品分類の昇順で抽出する。となる。 -
他の主な集計関数
SELECT 商品, avg(売上金額), min(売上金額), max(売上金額) FROM product_table GROUP BY 商品名;
avgは平均、maxは最大値、minは最小値を出力する。
上記のように集計関数は複数あってもOK。
SELECT 商品, count (売上金額) FROM product_table GROUP BY 商品名;
グルーピングされたレコードの行数を取得する集約関数。
このSQLを実行すると、商品名の同じレコードがいくつあるのかを出力される。
また、count関数はテーブル内にいくつのレコードがあるのかを出力する場合もよく使用される。
SELECT count (*) FROM product_table;
カラム名を指定せずに*を指定すると、テーブルの全件データ数を取得できる。
テーブルの全件数を知りたい場合に頻繁に使用する。
HAVING
グルーピングされたデータの中から、さらに特定の条件でデータ抽出したいときに使用する。
SELECT
グルーピングをするカラム,集約関数(集計対象カラム)
FROM
テーブル名
WHERE
条件式
GROUP BY
グルーピングをするカラム
HAVING
集計関数(集計対象カラム)で条件式
ORDER BY
並べ替え条件式;
SELECT 商品名,sum(売上金額) FROM product_table GROUP BY 商品名 HAVING sum(売上金額) >= 100000;
上記SQLを実行すると、売上金額が10万円以上の商品名のみ抽出することができる。
HAVINGに集約関数を含んだカラムを直接条件式に入れ込むことで、HAVINGを元にしたデータ抽出できる。
- WHEREとの違い
WHEREが単純にテーブル内のデータを抽出。
HAVINGはグルーピングしたデータからさらに抽出条件を付けられる。
しかし、WHEREもHAVINGもやっていることは同じで、どちらもデータに対して抽出処理を実行される。
異なるのは呼ばれるタイミングのみ。
【実行順番】
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY で、
『どのテーブルの(FROM)、どのデータを(WHERE)、どうグルーピングし(GROUP BY)、グルーピングしたデータをどう抽出し(HAVING)、どのカラム を(SELECT)、どう表示するか(ORDER BY)」の順番で実行。
WHEREはGROUP BYよりも前に、HAVINGはGROUP BYの後に実行される。
HAVINGは、GROUP BYされた後のデータに抽出条件を付与するため、集計関数を使用できる。
WHEREは、GROUP BYされる前にデータに抽出条件を付与するため、集計関数を使用できない。
以上を踏まえ、下記のSQLを実行すると、
SELECT 商品名 , sum(売上金額) FROM product_table WHERE 商品名 !='パンツ' GROUP BY 商品名 HAVING sum(売上金額) <= 100000;
パンツ以外の売上金額の合計を集計し、売上金額が10万円以下のみのデータを抽出される。
JOIN
テーブルとテーブルを結合する
JOINの種類
- 内部結合
inner join - 外部結合
left join
right join
outer join
内部結合では、on句で指定した条件に一致するレコードのみSQLの実行結果に表示
外部結合ではon句で指定した条件に一致しないレコードも実行結果に表示され、FROMを指定したテーブルのレコードをすべて抽出される。
INNER JOIN
SELECT カラム名
FROM テーブル名A(テーブル名 as Aの意味)
INNER JOIN テーブル名B(テーブル名 as Bの意味) → FROMとWHEREの間に記述
ON A.キー = B.キー → 「どのカラムで結合するか」を指定
WHERE 条件式;
例)
テーブル1:testA
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
テーブル2:testB
| 氏名 | 出席番号 | 国語 |
|---|---|---|
| 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 |
| 伊藤 | 5 | 80 |
| 渡邊 | 6 | 50 |
SELECT
A.氏名, A.数学, B.国語
FROM
testA as A → 別名をつけている
INNER JOIN
testB as B → 別名をつけている
ON
A.氏名 = B.氏名
上記のSQLを実行すると
| 氏名 | 出席番号 | 数学 | 国語 |
|---|---|---|---|
| 鈴木 | 1 | 50 | 70 |
| 佐藤 | 2 | 60 | 60 |
SELECTのA.氏名は「testAテーブルの氏名のカラム」
A.数学は「testAテーブルの数学のカラム」
B.国語は、「testBテーブルの国語のカラム」からデータを取得し、両方のテーブルからデータを同時に取得できるようになる。
ONは、どのカラムで結合するかを指定するので、
A.氏名でtestAテーブルのカラムの氏名、B.氏名でtestBテーブルのカラムの氏名をキーにして結合
それぞれのテーブルの氏名では、鈴木と佐藤が共通するレコードなので、この2つのレコードが抽出される。
LEFT JOIN
SELECT カラム名
FROM テーブル名A(テーブル名 as Aの意味)
LEFT JOIN テーブル名B(テーブル名 as Bの意味) → FROMとWHEREの間に記述
ON A.キー = B.キー → 「どのカラムで結合するか」を指定
WHERE 条件式;
例)
テーブル1:testA
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
テーブル2:testB
| 氏名 | 出席番号 | 国語 |
|---|---|---|
| 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 |
| 伊藤 | 5 | 80 |
| 渡邊 | 6 | 50 |
SELECT * → すべてのカラムを指定
FROM testA A → 別名をつけている
LEFT JOIN testB B → 別名をつけている
ON A.氏名 = B.氏名 → 両方のテーブルに存在する氏名のカラムを指定
上記のSQLを実行すると
| 氏名 | 出席番号 | 数学 | 氏名 | 出席番号 | 国語 |
|---|---|---|---|---|---|
| 鈴木 | 1 | 50 | 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 | 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 | NULL | NULL | NULL |
| 田中 | 4 | 80 | NULL | NULL | NULL |
このようにLEFT JOINでは、testAのテーブル(FROMで指定したテーブル)を基準として、もう1つのテーブルを結合させる。
on句で指定した氏名で、キーとして結合できなかったレコードはNULLとして補完される。
RIGHT JOIN(外部結合)
SELECT カラム名
FROM テーブル名A(テーブル名 as Aの意味)
RIGHT JOIN テーブル名B(テーブル名 as Bの意味) → FROMとWHEREの間に記述
ON A.キー = B.キー → 「どのカラムで結合するか」を指定
WHERE 条件式;
例)
テーブル1:testA
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
テーブル2:testB
| 氏名 | 出席番号 | 国語 |
|---|---|---|
| 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 |
| 伊藤 | 5 | 80 |
| 渡邊 | 6 | 50 |
SELECT * → すべてのカラムを指定
FROM testA A → 別名をつけている
RIGHT JOIN testB B → 別名をつけている
ON A.氏名 = B.氏名 → 両方のテーブルに存在する氏名のカラムを指定
上記のSQLを実行すると
| 氏名 | 出席番号 | 数学 | 氏名 | 出席番号 | 国語 |
|---|---|---|---|---|---|
| 鈴木 | 1 | 50 | 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 | 佐藤 | 2 | 60 |
| NULL | NULL | NULL | 伊藤 | 5 | 80 |
| NULL | NULL | NULL | 渡辺 | 6 | 50 |
このようにRIGHT JOINでは、testBのテーブル(RIGHT JOINで指定したテーブル)を基準として、もう1つのテーブルを結合させる。
on句で指定した氏名で、キーとして結合できなかったレコードはNULLとして補完される。
LEFT JOIN、RIGHT JOINは相互に書き換え可能なため、自分が使いやすい方を使用して構わない。
混在させてはいけない。
FULL OUTER JOIN(OUTER JOIN)
SELECT カラム名
FROM テーブル名A(テーブル名 as Aの意味)
OUTER JOIN テーブル名B(テーブル名 as Bの意味) → FROMとWHEREの間に記述
ON A.キー = B.キー → 「どのカラムで結合するか」を指定
WHERE 条件式;
テーブル1:testA
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
テーブル2:testB
| 氏名 | 出席番号 | 国語 |
|---|---|---|
| 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 |
| 伊藤 | 5 | 80 |
| 渡邊 | 6 | 50 |
SELECT * → すべてのカラムを指定
FROM testA A → 別名をつけている
OUTER JOIN testB B → 別名をつけている
ON A.氏名 = B.氏名 → 両方のテーブルに存在する氏名のカラムを指定
上記のSQLを実行すると
| 氏名 | 出席番号 | 数学 | 氏名 | 出席番号 | 国語 |
|---|---|---|---|---|---|
| 鈴木 | 1 | 50 | 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 | 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 | NULL | NULL | NULL |
| 田中 | 4 | 80 | NULL | NULL | NULL |
| NULL | NULL | NULL | 伊藤 | 5 | 80 |
| NULL | NULL | NULL | 渡辺 | 6 | 50 |
ベン図

このようにOUTER JOINでは、すべてのレコードが表示される。
on句で指定した氏名で、キーとして結合できなかったレコードはNULLとして補完される。
AND演算子 OR演算子(論理演算子)
2つ以上の条件式を組み合わせてデータ抽出を行う際に使用
AND
SELECT カラム名
FROM テーブル名
WHERE 条件式A AND 条件式B; → 条件式Aかつ条件式Bという条件が成立
例)
SELECT
*
FROM
product_table
WHERE
商品分類 ='パンツ' AND 単価 >= 5000;
上記のSQLを実行すると・・・
『商品分類がパンツ』、『単価が5000円以上』の両方を満たすレコードが抽出される。
OR
SELECT カラム名
FROM テーブル名
WHERE 条件式A OR 条件式B; → 条件式Aまたは条件式Bという条件が成立
例)
SELECT
*
FROM
product_table
WHERE
商品分類 ='パンツ' OR 単価 >= 5000;
上記のSQLを実行すると・・・
『商品分類がパンツ』、『単価が5000円以上』のどちらかを満たすレコードがすべて抽出される。
AND演算子とOR演算子を併用する場合
AND演算子がOR演算子よりも優先されるため、注意が必要
例)
『商品分類がパンツ』または、『単価が5,000円以上』かつ『売上金額が500,000円以上』という条件で抽出したい場合
下記のSQLを実行する
SELECT
*
FROM
product_table
WHERE
(商品分類 ='パンツ' OR 単価 >= 5000) AND 売上金額 >= 500000;
()の中の条件式が優先されるため、意図した通りに実行結果が得られる。
LIKE演算子
パターンマッチングを行い、
データ群の中からある特定のパターンに一致あるいは類似するデータを探し出すことができる。
SELECT カラム名
FROM テーブル名
WHERE カラム LIKE パターンマッチングの条件; → ワイルドカードを使用する
ワイルドカード
_ (アンダーバー) : 任意の1文字の文字列(文字数を指定したい場合に使用)
% : 0文字以上の任意の文字列
例)テニスボール、サッカーボール、バレーボール、ボウリングと4つの球があったとする。
『%ボール』とすると・・・テニスボール、サッカーボール、バレーボールの3つの球が抽出される。
『___(アンダーバー3つ)ボール』とすると・・・テニスボール、バレーボールの2つのみ抽出される。
前方一致
例)
countryテーブル
| ID | 国名 | 首都 |
|---|---|---|
| 1 | Argentina | Buenos Aires |
| 2 | Australia | Canberra |
| 3 | Belgium | Brussels |
| 4 | Japan | Tokyo |
| 5 | China | Beijing |
国名が『A』から始まるレコードを抽出する場合
SELEC *
FROM country
WHERE 国名 LIKE ‘A%’;
上記のSQLを実行すると・・・Argentina、Australiaの2つの国が抽出される
後方一致
例)
countryテーブル
| ID | 国名 | 首都 |
|---|---|---|
| 1 | Argentina | Buenos Aires |
| 2 | Australia | Canberra |
| 3 | Belgium | Brussels |
| 4 | Japan | Tokyo |
| 5 | China | Beijing |
国名が『a』で終わるレコードを抽出する場合
SELEC *
FROM country
WHERE 国名 LIKE ‘%a’;
上記のSQLを実行すると・・・Argentina、Australia、Chinaの3つの国が抽出される
前方一致かつ後方一致
例)
countryテーブル
| ID | 国名 | 首都 |
|---|---|---|
| 1 | Argentina | Buenos Aires |
| 2 | Australia | Canberra |
| 3 | Belgium | Brussels |
| 4 | Japan | Tokyo |
| 5 | China | Beijing |
国名が『C』から始まり、『a』で終わるレコードを抽出する場合
SELEC *
FROM country
WHERE 国名 LIKE ‘A%a’;
上記のSQLを実行すると・・・Chinaのみ抽出される
部分一致
例)
countryテーブル
| ID | 国名 | 首都 |
|---|---|---|
| 1 | Argentina | Buenos Aires |
| 2 | Australia | Canberra |
| 3 | Belgium | Brussels |
| 4 | Japan | Tokyo |
| 5 | China | Beijing |
国名に『a』を含むレコードを抽出する場合
SELEC *
FROM country
WHERE 国名 LIKE ‘%a%’;
上記のSQLを実行すると・・・Argentina、Australia、Japan、Chinaの4つの国が抽出される
NOT LIKE
例)
countryテーブル
| ID | 国名 | 首都 |
|---|---|---|
| 1 | Argentina | Buenos Aires |
| 2 | Australia | Canberra |
| 3 | Belgium | Brussels |
| 4 | Japan | Tokyo |
| 5 | China | Beijing |
国名に『a』を含まないレコードを抽出する場合
SELEC *
FROM country
WHERE 国名 NOT LIKE ‘%a%’;
上記のSQLを実行すると・・・Belgiumのみが抽出される
ワイルドカードのエスケープ処理
例)
productテーブル
| ID | 商品ID | 商品 |
|---|---|---|
| 1 | A_1000 | Tシャツ |
| 2 | A_2000 | ジーンズ |
| 3 | A_2010 | ショートパンツ |
| 4 | B_1000 | ロングパンツ |
| 5 | B_1010 | ダウンジャケット |
商品IDに『_1』を含むレコードを抽出する場合
SELEC *
FROM product
WHERE 商品ID LIKE ‘%?_1%’ ESCAPE ‘?’;
上記のSQLを実行すると・・・A_1000のみが抽出される
ワイルドカードの『 % 』や『 _ 』は、特殊文字になるため、
WHERE 商品ID LIKE ‘%_1%’このような記述では意図したレコードは抽出されない。
エスケープ処理を忘れないように。
特殊文字とは・・・
プログラム上で何らかの意味を持ち、そのままでは文字列として扱われない文字のこと
BETWEEN
範囲指定をするときに使用。
範囲指定できるもの:数値・日付・時間・文字列など
SELECT カラム名
FROM テーブル名
WHERE カラム名 BETWEEN 下限値 AND 上限値;
上記構文は、
SELECT カラム名
FROM テーブル名
WHERE カラム名 >= 下限値 AND [カラム名] <= 上限値;
と同様になるため、指定範囲の値を条件として抽出できる。
NOT BETWEEN
SELECT カラム名
FROM テーブル名
WHERE カラム名 NOT BETWEEN 下限値 AND 上限値;
指定範囲外の値を条件にして抽出できる。
例)bakery_shop
| 商品名 | 売上金額 | 売上日 |
|---|---|---|
| クリームパン | 5,000 | 2022-10-17 |
| 食パン | 3,000 | 2022-10-25 |
| あんぱん | 6,000 | 2022-10-07 |
| カレーパン | 4,000 | 2022-10-30 |
| メロンパン | 3,500 | 2022-11-01 |
『売上金額が、4,000円以上6,000円以下』のデータを抽出するには下記のSQLを実行する。
SELECT 商品名, 売上金額 FROM bakery_shop WHERE 売上金額 BETWEEN 4000 AND 6000;
実行結果は下記になる。
| 商品名 | 売上金額 |
|---|---|
| クリームパン | 5,000 |
| カレーパン | 4,000 |
| あんぱん | 6,000 |
『売上日が、2022-10-17から2022-10-30まで』のデータを抽出するには下記のSQLを実行。
SELECT * FROM bakery_shop WHERE 売上日 BETWEEN ‘2022-10-17’ AND ‘2022-10-30’;
実行結果(すべてのカラムを選択しているので、売上金額も抽出される)
| 商品名 | 売上金額 | 売上日 |
|---|---|---|
| クリームパン | 5,000 | 2022-10-17 |
| 食パン | 3,000 | 2022-10-25 |
| カレーパン | 4,000 | 2022-10-30 |
『売上金額が、4,000円以上6,000円以下』以外のデータを抽出するには下記のSQLを実行する。
SELECT 商品名, 売上金額 FROM bakery_shop WHERE 売上金額 NOT BETWEEN 4000 AND 6000;
実行結果は下記になり、NOT BETWEENは指定された範囲外の抽出に使用できる。
| 商品名 | 売上金額 |
|---|---|
| 食パン | 3,000 |
| メロンパン | 3,500 |
LENGTH関数
LENGTH関数は、引数に指定した文字列の文字数を取得。
LENGTH(引数)
引数・・・文字列:文字数
BLOB型:バイト数
上記以外:文字列型に変換した文字数
NULL:NULL
BLOB型はバイナリデータの格納に使用されるデータ型で、BLOBとはBinary Large Objectという意味。
BLOB型の例は、画像や音声などのマルチメディアオブジェクトをバイナリデータに変換したもの。
引数が文字列やBLOB型でない場合は、一度文字列に変換したうえで文字数を取得。
引数がNULLの場合は、NULLが返ってくる。
SELECT LENGTH(カラム) → カラムの値の文字数を取得
FROM テーブル;
例)bakery_shop
| 商品名 | 売上金額 | 売上日 |
|---|---|---|
| クリームパン | 5,000 | 2022-10-17 |
| あんぱん | 6,000 | 2022-10-07 |
| カレーパン | 4,000 | 2022-10-30 |
| メロンパン | 3,500 | 2022-11-01 |
SELECT
商品名, LENGTH(商品名)文字数 → 商品名のカラムと商品名の文字数を新しいカラムの『文字数』で取得
FROM
bakery_shop;
上記SQLを実行
| 商品名 | 文字数 |
|---|---|
| クリームパン | 6 |
| あんぱん | 4 |
| カレーパン | 5 |
| メロンパン | 5 |
指定した文字数以上のデータを抽出する場合は、条件抽出するためのWHERE句で使用
SELECT
商品名, LENGTH(商品名)文字数
FROM
bakery_shop
WHERE
LENGTH(商品名) >= 5; → 5文字以上のデータを抽出する
SQLを実行
| 商品名 | 文字数 |
|---|---|
| クリームパン | 6 |
| カレーパン | 5 |
| メロンパン | 5 |
5文字以上のデータを抽出された。
DISTINCT
値の重複を排除してカラムを抽出したいときに使用。
SELECT
distinct カラム1, カラム2,… → distinctを使って抽出したカラムは一意の値だけ残る
FROM
テーブル;
例) foods_table
| 商品分類 | 商品名 | 価格 |
|---|---|---|
| パン | カレーパン | 200 |
| 弁当 | からあげ弁当 | 500 |
| パン | カレーパン | 150 |
| 飲料 | 水 | 100 |
SELECT distinct 商品分類 FROM foods_table;
を実行すると
| 商品分類 |
|---|
| パン |
| 弁当 |
| 飲料 |
のように、値の重複(パンとパン)を排除して抽出される。
SELECT distinct 商品分類, 商品名 FROM foods_table;
と複数カラムを指定することもできる。
上記を実行すると
| 商品分類 | 商品名 |
|---|---|
| パン | カレーパン |
| 弁当 | からあげ弁当 |
| 飲料 | 水 |
のように、値の重複(パンとパン、カレーパンとカレーパン)を排除して抽出される。
count関数と併用することもできる
SELECT count(distinct 商品分類) FROM foods_table;
を実行すると
| count(distinct 商品分類) |
|---|
| 3 |
となり、商品分類の重複を排除した『パン・弁当・飲料』の3種類存在するため、3という値が抽出される。
GROUP BYとの違い
DISTINCTは、『重複した値を排除』
GROUP BY句は、『重複した値を一つにまとめる』というイメージ。
例)
- DISTINCT
SELECT distinct 商品分類 FROM foods_table; - GROUP BY
SELECT 商品分類 FROM foods_table GROUP BY 商品分類;
上記SQL構文は、下記の結果になり、同じ結果が得られる。
| 商品分類 |
|---|
| パン |
| 弁当 |
| 飲料 |
DISTINCTもGROUP BYも一意の値が抽出されるのは、変わらないため、値の重複なしで抽出される。
しかし、GROUP BY句を使った集計関数は、DISTINCTで書き換えることはできない。
SELECT 商品分類, sum(価格) FROM foods_table GROUP BY 商品分類;
のように、GROUP BY句で商品分類のカラムを指定して、商品分類のカラムの値ごとに価格のカラムをSUM関数で集計する処理は、DISTINCTでは向いていないため、GROUP BY句を使いましょう。
SUBSTRING関数
対象の文字列から、開始位置と文字数を指定して、一部文を切り出すことができる関数。
substring(文字列(もしくは、カラム名), 開始位置, 文字数)
第一引数:対象の文字列もしくは、カラムを指定。
第二引数:文字列を切り出す開始位置を整数で指定。
第三引数:開始位置から切り出したい文字数を指定。
第二引数について
+3であれば、最初の文字を1番目と数え、3文字目が開始位置になる。
-3であれば、最後の文字を1番目と数え、3文字前が開始位置になる。
例)bakery_shop
| 商品名 | 売上金額 | 売上日 |
|---|---|---|
| クリームパン | 5,000 | 2022-10-17 |
| あんぱん | 6,000 | 2022-10-07 |
| カレーパン | 4,000 | 2022-11-02 |
| メロンパン | 3,500 | 2022-11-30 |
売上日の月ごとの売上金額の合計を出したい場合
SELECT
substring(“売上日”, 6, 2) as 月,
sum(“売上金額”) as 売上合計
FROM
bakery_shop
GROUP BY 月;
上記SQLを実行すると
| 月 | 売上金額 |
|---|---|
| 10 | 11,000 |
| 11 | 7,500 |
売上金額を月ごとに集計できた。
ROUND関数
数値を指定した桁数の四捨五入に使用。
ROUND(数値, 桁数)
第一引数:四捨五入の対象となる数値もしくはカラムを指定
カラムを指定した場合、カラムのすべての数値が四捨五入の対象になる。
第二引数:四捨五入を行う桁数を指定
桁数を指定しない場合、0が指定されたものとなり整数が表示される
第一引数、第二引数のどちらかにNULLが入ると、NULLを返す
例)test-results_table
あるクラスのテスト結果の平均点数を表すテーブル
| 科目名 | 平均点数 |
|---|---|
| 数学 | 60.25 |
| 国語 | 72.333 |
| 社会 | 65.5 |
| 英語 | 55.2 |
| 化学 | 58.25 |
- 少数を省力し、整数のみ表示する場合
SELECT
科目名,平均点数, ROUND(平均点数) as 四捨五入値 → 第二引数を省略もしくは0とする
FROM
test-results_table;
上記SQLを実行すると
| 科目名 | 平均点数 | 四捨五入値 |
|---|---|---|
| 数学 | 60.25 | 60 |
| 国語 | 72.333 | 72 |
| 社会 | 65.5 | 66 |
| 英語 | 55.2 | 55 |
| 化学 | 58.25 | 58 |
第一小数点が四捨五入され、整数のみ抽出される。
- 第一小数点まで表示する
SELECT
科目名,平均点数, ROUND(平均点数, 1) as 四捨五入値 → 第二引数を1とする
FROM
test-results_table;
上記SQLを実行すると
| 科目名 | 平均点数 | 四捨五入値 |
|---|---|---|
| 数学 | 60.25 | 60.3 |
| 国語 | 72.333 | 72.3 |
| 社会 | 65.5 | 65.5 |
| 英語 | 55.2 | 55.2 |
| 化学 | 58.25 | 58.3 |
第二小数点が四捨五入され、第一小数点でまで表示される。
- 第二小数点まで表示する
SELECT
科目名,平均点数, ROUND(平均点数, 2) as 四捨五入値 → 第二引数を2とする
FROM
test-results_table;
上記SQLを実行すると
| 科目名 | 平均点数 | 四捨五入値 |
|---|---|---|
| 数学 | 60.25 | 60.25 |
| 国語 | 72.333 | 72.33 |
| 社会 | 65.5 | 65.5 |
| 英語 | 55.2 | 55.2 |
| 化学 | 58.25 | 58.25 |
第三小数点が四捨五入され、第二小数点まで表示される。
CASE式
If Else構文のような条件分岐を行いたいときに使用。
CASE式には2種類の条件分岐の式がある。
単純CASE式
カラムの値が指定した値と等価であるか判定し、処理の分岐を行う。
CASE カラム → 対象になるカラムを書く
WHEN 値1 THEN 結果1 → カラムの値に基づき処理を分岐(WHEN句に等価の場合、THENの値)
WHEN 値2 THEN 結果2
WHEN 値3 THEN 結果3
ELSE 結果4 → WHEN句で指定した値のどれも一致しない場合の結果を、ELSE句に書く
END
検索CASE式
等価判定以外にもさまざまな条件で処理を分岐させる。
CASE → 対象となるカラムを書かない
WHEN 条件式1 THEN 結果1 → WHEN句で条件式を書いて、条件式がtrueのときTHENを返す
WHEN 条件式2 THEN 結果2
WHEN 条件式3 THEN 結果3
ELSE 結果4
END
例)test-results_table
あるクラスのテスト評価を氏名ごとに記載されたテーブル
| 氏名 | 英語(5点評価) |
|---|---|
| 田中 | 5 |
| 鈴木 | 3 |
| 高橋 | 3 |
| 伊藤 | 1 |
| 佐藤 | 4 |
評価に基づいて成績を1であればC、5であればA、それ以外であればBと振り分けるとする。
- 単純CASE式の場合
SELECT *
CASE 英語 → 対象カラムを書く
WHEN 1 THEN ‘C’
WHEN 5 THEN ‘A’
END 成績 → 別名をつける場合はENDの後に
FROM test-results_table;
| 氏名 | 英語(5点評価) | 成績 |
|---|---|---|
| 田中 | 5 | A |
| 鈴木 | 3 | B |
| 高橋 | 3 | B |
| 伊藤 | 1 | C |
| 佐藤 | 4 | B |
このように、条件通り抽出できる。
- 検索CASE式の場合
SELECT *
CASE
WHEN 英語 = 1 THEN ‘C’ → 条件式にカラムを指定する
WHEN 英語 = 5 THEN ‘A’
END 成績 → 別名をつける場合はENDの後に
FROM test-results_table;
| 氏名 | 英語(5点評価) | 成績 |
|---|---|---|
| 田中 | 5 | A |
| 鈴木 | 3 | B |
| 高橋 | 3 | B |
| 伊藤 | 1 | C |
| 佐藤 | 4 | B |
このように、条件通り抽出できる
- CASE式を入れ子として使用する
products_table
| 商品名 | 売上日 | 売上金額 |
|---|---|---|
| ロングパンツ | 2022-10-20 | 9000 |
| ジーンズ | 2022-10-05 | 10000 |
| セーター | 2022-11-10 | 3000 |
| ジャケット | 2022-11-15 | 2000 |
| ショートパンツ | 2022-10-01 | 2000 |
10月中の売上に対してのみ、売上金額が1万円以上には、3,000円のキャッシュバック、8,000円以上には2,000円のキャッシュバック、それ以外は500円のキャッシュバック、10月以外はキャッシュバックを0とする。
SELECT *
CASE
WHEN 売上日 BETWEEN ‘2022-10-1’ AND ‘2022-10-31’ THEN
CASE
WHEN 売上金額 >= 10000 THEN 3000
WHEN 売上金額 >= 8000 THEN 2000
ELSE 0
END
ELSE 0
END キャッシュバック
FROM products_table;
上記SQL実行すると
| 商品名 | 売上日 | 売上金額 | キャッシュバック |
|---|---|---|---|
| ロングパンツ | 2022-10-20 | 9000 | 2000 |
| ジーンズ | 2022-10-05 | 10000 | 3000 |
| セーター | 2022-11-10 | 3000 | 0 |
| ジャケット | 2022-11-15 | 2000 | 0 |
| ショートパンツ | 2022-10-01 | 2000 | 500 |
想定通りの結果が得られた。
このように、CASE式を入れ子にすることも可能。
サブクエリ
一つのSQLの実行結果をもとに、また別のSQLで抽出を行いたい時、
2段階以上の集計を1つのクエリに簡単にまとめることができる。
サブクエリは、1つのSQLをカッコで括ったもの。
SELECT
カラムA, SUM(カラムB<integer>)
FROM
(SELECT → サブクエリ
カラムA, カラムB<integer>
FROM
テーブル
WHERE
条件式)
GROUP BY カラムA
テーブルからAというカラムとBという数値が入ったカラムを条件式によって抽出され、FROM句でカラムAごとの数値の合計を計算。
SELECT
テーブルC.カラムA,
テーブルC.カラムB,
テーブルD.カラムE
FROM
(SELECT → サブクエリ
カラムA,カラムB
FROM
テーブルC
WHERE
条件式)
JOIN
テーブルD
ON
テーブルC.カラムA = テーブルD.カラムA;
テーブルCからカラムAとBを抽出、これをJOIN句でテーブルDと結合し、テーブルCとカラムAとB、テーブルDのカラムEを抽出している。
例)
テーブル1:testA
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
テーブル2:testB
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 80 |
| 田中 | 4 | 50 |
数学の点数が60点以下の人の国語の点数がいくつなのか抽出するには、以下のSQLを実行する
SELECT
testA.氏名,
testB.出席番号,
数学,
国語
FROM
(SELECT → testAのテーブルから数学の点数が60点以下の人を抽出
*
FROM
testA
WHERE
数学 <= 60)
testA
JOIN → testBのテーブルを、どちらのテーブルにもある出席番号で結合
testB
on
testA.出席番号 = testB.出席番号;
| 氏名 | 出席番号 | 数学 | 国語 |
|---|---|---|---|
| 鈴木 | 1 | 50 | 70 |
| 佐藤 | 2 | 60 | 60 |
| 高橋 | 3 | 40 | 80 |
となり、サブクエリの条件式を加えたデータ抽出が行える。
IN句
複数のOR条件を1つにまとめて記述でき、
カラムの値が指定した値のリストのいずれかに一致するという条件を作ることができる。
SELECT
*
FROM
テーブル
WHERE
カラム IN (値1,値2,値3...);
WHERE句で条件を適用するカラムを記述し、IN句を記述する。
逆に、値のいずれにも一致しないという条件は下記になる。
SELECT
*
FROM
テーブル
WHERE
カラム NOT IN (値1,値2,値3...); → カッコ内のカラムの値がいずれかに一致するとなる
例)
テーブル1:testA
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
氏名が鈴木、佐藤、今野のいずれかで当てはまるレコードを抽出したい場合
SELECT
*
FROM
testA
WHERE
氏名 IN(‘鈴木’, ‘佐藤’, ‘今野’); → WHERE句にIN句で複数の条件を指定する
上記SQLを実行すると
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
IN句で指定した条件のみ抽出される。
氏名が鈴木、佐藤、今野のいずれかにも当てはまらないレコードを抽出したい場合
SELECT
*
FROM
testA
WHERE
氏名 NOT IN(‘鈴木’, ‘佐藤’, ‘今野’); → WHERE句にIN句で複数の条件を指定する
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
と氏名が鈴木、佐藤、今野以外の氏名の方が抽出される。
サブクエリを使用する場合
テーブル1:testA
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 40 |
| 田中 | 4 | 80 |
テーブル2:testB
| 氏名 | 出席番号 | 国語 |
|---|---|---|
| 鈴木 | 1 | 70 |
| 佐藤 | 2 | 60 |
| 高橋 | 3 | 80 |
| 田中 | 4 | 50 |
testBで国語の点数が70点以上のtestAの氏名のいずれかに一致するというレコードを抽出したい場合
SELECT
*
FROM
testA
WHERE
氏名 IN(SELECT 氏名 FROM testB WHERE 国語 >= 70); → サブクエリで、testBの国語の点数が70点以上の氏名を抽出
| 氏名 | 出席番号 | 数学 |
|---|---|---|
| 鈴木 | 1 | 50 |
| 高橋 | 3 | 40 |
国語の点数が70点以上は、鈴木と高橋のみであるため、上記のレコードが抽出される。
LIMIT
SQLを実行する時に取得するデータの最大数を設定できる関数。
SELECT
カラム名
FROM
テーブル
LIMIT
設定レコード数; → LIMIT関数で設定したレコードより少ない場合、全データが抽出される
OFFSET関数との組み合わせ
OFFSET関数は、データを取得する開始位置を指定することができる関数のこと
SELECT
カラム名
FROM
テーブル
LIMIT
設定レコード数 OFFSET 取得開始行 - 1; → 取得したい行数からマイナス1した数を指定
例)
「売上金額の合計」が高い商品順の4番目から3レコードのデータを抽出したい場合
SELECT
商品名,
SUM(売上金額) as 売上合計 → 売上金額の合計を抽出
FROM
Products_table
GROUP BY
商品名 → 売上金額を商品ごとにグループにして集計
ORDER BY
売上合計 desc → 売上金額を高い順に並び替える
LIMIT 3 OFFSET 3; → レコード数を3、4番目を開始位置として指定したいので、4番目のマイナス1である3を指定




