SELECT文の実行順序
AS を使って列に名前を付けられるようになりました。ところがその名前を WHERE で使おうとすると、多くのデータベースで「そんな列は無い」と言われます。
付けたはずの別名が、WHERE からは見えない
SQL クエリ
-- 税込価格が 5000 円を超える本を探したい
SELECT title, price * 1.10 AS price_with_tax
FROM books
WHERE price_with_tax > 5000;書いた順序では SELECT が先頭にあるので、price_with_tax はもう存在しているように見えます。しかし SQL は書いた順には実行されません。WHERE が動くのは SELECT よりずっと前で、その時点では別名がまだ生まれていないのです。
回避するには、式をそのまま書き直します。
SQL クエリ
SELECT title, price * 1.10 AS price_with_tax
FROM books
WHERE price * 1.10 > 5000;ORDER BY なら、同じ別名がそのまま使える
SQL クエリ
SELECT title, price * stock AS inventory_value
FROM books
ORDER BY inventory_value DESC;ORDER BY は出力する列が決まったあと、つまり SELECT より後に動きます。別名はもう存在しているので、そのまま参照できます。使える句と使えない句がある理由は、この前後関係だけです。
実際に動く順番
読み込み (FROM) から始まり、行を絞り (WHERE)、グループに束ね (GROUP BY)、集計し、グループを絞り (HAVING)、出力する列を決め (SELECT)、並べ替え (ORDER BY)、上から必要な数だけ切り出します (LIMIT)。
この順番が分かっていると、もう一つのよくあるエラーも読めます。
SQL クエリ
-- 集計はまだ終わっていないので、ここでは使えない
SELECT genre, SUM(price)
FROM books
WHERE SUM(price) >= 10000
GROUP BY genre;WHERE が動く時点では、まだ 1 行 1 行がばらばらのままです。合計という値が生まれるのはもっと後なので、WHERE からは触れません。集計し終わったあとで絞りたいなら HAVING の出番です。
エラーが出たら「その値は、この句が動く時点でもう存在しているか」を考えてみてください。実行順序がらみの詰まりは、ほぼこれで説明が付きます。
テーブル構造
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
category VARCHAR(30) NOT NULL,
price INT NOT NULL
);
INSERT INTO products (id, name, category, price) VALUES
(1, 'ノートPC', '家電', 128000),
(2, 'マウス', '家電', 2980),
(3, 'キーボード', '家電', 6800),
(4, '小説A', '書籍', 1800),
(5, '小説B', '書籍', 2200),
(6, '専門書A', '書籍', 4500),
(7, 'コーヒー豆', '食品', 1500),
(8, '紅茶葉', '食品', 1200);期待される出力
| category | total |
|---|---|
| 家電 | 137780 |
| 書籍 | 8500 |