Kodokon kodokon.com

サブクエリ:WHERE、FROM、IN、EXISTS

あるクエリを別のクエリの中に入れ子にして、集計値と比較したり、集合で絞り込んだり、存在をテストしたりしましょう。

9 分 · 3 問

このレッスンを Kodokon で開く

サブクエリとは、別のクエリの中の丸括弧に置かれたクエリのことです。一つの文で「平均より上の注文」や「少なくとも一つ注文のある顧客」といった問いに答えます。始める前に、このスクリプトを sqliteonline.com か sqlite3 で実行しましょう。

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  amount REAL NOT NULL
);

INSERT INTO customers (id, name) VALUES
  (1, 'Alice'), (2, 'Karim'),
  (3, 'Mina'), (4, 'Paulo');

INSERT INTO orders (id, customer_id, amount)
VALUES
  (1, 1, 49.90), (2, 1, 15.00),
  (3, 2, 120.50), (4, 2, 80.00),
  (5, 3, 9.90), (6, 1, 200.00);
データセット:四人の顧客、六件の注文。

WHERE に置かれたスカラーサブクエリは、単一の値、つまり一行一列を返さなければなりません。エンジンはまずそれを計算し、それから他の定数と同じように使います。単純な WHERE amount > AVG(amount) ではこれはできません。SQLでは禁じられているのです。

SQL
SELECT id, customer_id, amount
FROM orders
WHERE amount > (
  SELECT AVG(amount) FROM orders
);
平均の買い物かご(79.22)より上の注文。

IN は、列を、サブクエリが返す値の集合と比較します。EXISTS は、相関サブクエリ(外側のクエリの列である c.id を参照します)が少なくとも一行を返すかどうかをテストします。エンジンは最初の一致が見つかったらすぐに止まります。

SQL
SELECT name FROM customers
WHERE id IN (
  SELECT customer_id FROM orders
  WHERE amount > 100
);

SELECT c.name FROM customers AS c
WHERE EXISTS (
  SELECT 1 FROM orders AS o
  WHERE o.customer_id = c.id
);
IN:たくさん使う顧客。EXISTS:活動中の顧客。

FROM の中では、サブクエリは一時的なテーブルのように振る舞い、導出テーブルと呼ばれ、エイリアスを付けなければなりません。二段階で集計するための定番の道具です。まず顧客ごとの合計、次にそれらの合計の平均です。

SQL
SELECT ROUND(AVG(t.total), 2) AS avg_basket
FROM (
  SELECT customer_id, SUM(amount) AS total
  FROM orders
  GROUP BY customer_id
) AS t;
活動中の顧客ごとの買い物かご合計の平均:158.43。

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. amount > (...) で使われるサブクエリは、いくつの値を返さなければなりませんか?
    • ちょうど一つ
    • 外側のテーブルの行ごとに一つ
    • 好きなだけいくつでも
  2. IN に対する EXISTS の主な利点は何ですか?
    • 複数の列を返せる
    • 集合全体を作り出すことなく、最初に見つかった行で止まる
    • サブクエリなしで動く
  3. FROM に置かれたサブクエリが、どこでも移植可能であるために常に備えていなければならないものは何ですか?
    • AS t のようなエイリアス
    • ORDER BY 句
    • 内部のセミコロン