SQL

検索と集計

必要な行を選び、値を分類し、まとまりごとの件数や合計を求めましょう。

01

練習データを確認する

SQL入門で作ったproductsを使います。詳細ページだけを読む場合は、先に基礎ページのCREATE TABLEINSERTを実行してください。

全商品を確認SQL
SELECT id, name, price, category, stock
FROM products
ORDER BY id;
実行結果OUTPUT
id  name        price  category    stock
--  ----------  -----  ----------  -----
1   SQL入門書   2800   book        5
2   ノート       300   stationery  12
3   ボールペン   150   stationery  0
4   マグカップ   900               3

SQLiteの通常表示ではNULLが空欄に見えることがあります。空文字が保存されているとは限りません。

02

条件を小さく組み立てる

検索条件は、対象を言葉で整理してから書きます。次は「分類が文房具」「または分類が未設定」のうち、「在庫がある」商品です。

ANDとORを組み合わせるSQL
SELECT name, category, stock
FROM products
WHERE (category = 'stationery' OR category IS NULL)
  AND stock > 0
ORDER BY id;
実行結果OUTPUT
name        category    stock
----------  ----------  -----
ノート      stationery  12
マグカップ              3

部分一致を使う

LIKEでは、%が0文字以上の任意の文字、_が任意の1文字を表します。

名前に「入門」を含む商品SQL
SELECT name FROM products WHERE name LIKE '%入門%';
実行結果OUTPUT
name
---------
SQL入門書
利用者の入力を連結しない アプリで検索語を受け取る場合もSQL文字列へ直接つなげず、利用する言語のプレースホルダー機能へ値を渡します。
03

CASE式で値を分類する

CASE式は条件に応じた値を返します。上から順に調べ、最初に一致したTHENの値を使います。

在庫状態を表示SQL
SELECT name, stock,
       CASE
           WHEN stock = 0 THEN '在庫切れ'
           WHEN stock <= 3 THEN '残りわずか'
           ELSE '在庫あり'
       END AS stock_status
FROM products
ORDER BY id;
実行結果OUTPUT
name        stock  stock_status
----------  -----  ------------
SQL入門書   5      在庫あり
ノート       12     在庫あり
ボールペン   0      在庫切れ
マグカップ   3      残りわずか

stock = 0を先に書かないと、stock <= 3にも一致して「残りわずか」になります。条件が重なるときは順番を確認します。

04

集計関数とNULL

COUNT(*)は行数を数えますが、COUNT(category)categoryがNULLの行を数えません。

数え方の違いSQL
SELECT COUNT(*) AS all_rows,
       COUNT(category) AS category_rows,
       SUM(stock) AS total_stock,
       ROUND(AVG(price), 1) AS average_price
FROM products;
実行結果OUTPUT
all_rows  category_rows  total_stock  average_price
--------  -------------  -----------  -------------
4         3              20           1037.5
0件のとき COUNTは0を返しますが、SUMAVGはNULLを返すことがあります。必要ならCOALESCE(SUM(stock), 0)とします。
05

GROUP BYでまとまりを作る

GROUP BY categoryは、同じ分類の行を一つのグループとして集計します。集計対象でない列を無関係にSELECTへ加えると、意味が曖昧になります。

分類別に集計SQL
SELECT COALESCE(category, '未分類') AS category_name,
       COUNT(*) AS count,
       SUM(stock) AS total_stock
FROM products
GROUP BY category
ORDER BY count DESC, category_name;
実行結果OUTPUT
category_name  count  total_stock
-------------  -----  -----------
stationery     2      12
book           1      5
未分類          1      3
06

WHEREとHAVINGを使い分ける

WHEREはグループを作る前の行を絞り、HAVINGは集計したあとのグループを絞ります。次は在庫がある商品のみを集計し、その合計在庫が4個以上の分類だけを返します。

集計前と集計後の条件SQL
SELECT category, SUM(stock) AS total_stock
FROM products
WHERE stock > 0
  AND category IS NOT NULL
GROUP BY category
HAVING SUM(stock) >= 4
ORDER BY category;
実行結果OUTPUT
category    total_stock
----------  -----------
book        5
stationery  12
PRACTICE

ミニ課題:価格帯別の商品数

CASEで500円未満を「低価格」、500円以上1000円未満を「中価格」、1000円以上を「高価格」に分け、価格帯ごとの商品数を表示してください。

解答例SQL
SELECT CASE
           WHEN price < 500 THEN '低価格'
           WHEN price < 1000 THEN '中価格'
           ELSE '高価格'
       END AS price_range,
       COUNT(*) AS product_count
FROM products
GROUP BY price_range
ORDER BY MIN(price);
実行結果OUTPUT
price_range  product_count
-----------  -------------
低価格        2
中価格        1
高価格        1