ซ้อนคิวรีหนึ่งไว้ในอีกคิวรีหนึ่งเพื่อเปรียบเทียบกับค่ารวม กรองด้วยชุดของค่า หรือทดสอบการมีอยู่
เปิดบทเรียนนี้ใน Kodokonซับคิวรี (subquery) คือคิวรีที่วางไว้ในวงเล็บภายในอีกคิวรีหนึ่ง ในคำสั่งเดียว มันตอบคำถามอย่างเช่น "คำสั่งซื้อที่สูงกว่าค่าเฉลี่ย" หรือ "ลูกค้าที่มีคำสั่งซื้ออย่างน้อยหนึ่งรายการ" รันสคริปต์นี้ใน sqliteonline.com หรือ sqlite3 ก่อนเริ่ม
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 ซับคิวรีแบบ สเกลาร์ (scalar) ต้องคืนค่าเดียว คือหนึ่งแถว หนึ่งคอลัมน์ เอนจินจะคำนวณมันก่อน แล้วจึงใช้มันเหมือนค่าคงที่ตัวอื่น ๆ คุณทำเช่นนี้ด้วย WHERE amount > AVG(amount) ธรรมดาไม่ได้ เพราะเป็นสิ่งต้องห้ามใน SQL
SELECT id, customer_id, amount
FROM orders
WHERE amount > (
SELECT AVG(amount) FROM orders
);IN เปรียบเทียบคอลัมน์กับ ชุด (set) ของค่าที่ซับคิวรีคืนกลับมา EXISTS ทดสอบว่าซับคิวรีแบบ สหสัมพันธ์ (correlated) (ซึ่งอ้างถึง c.id อันเป็นคอลัมน์ของคิวรีภายนอก) คืนอย่างน้อยหนึ่งแถวหรือไม่ เอนจินจะหยุดทันทีที่พบคู่ที่ตรงกันคู่แรก
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
);ใน FROM ซับคิวรีจะทำตัวเหมือนตารางชั่วคราวที่เรียกว่า ตารางอนุพัทธ์ (derived table) และต้องกำหนดนามแฝงให้ มันเป็นเครื่องมือคลาสสิกสำหรับการรวมกลุ่มแบบสองขั้น ขั้นแรกหายอดรวมต่อลูกค้าหนึ่งคน แล้วจึงหาค่าเฉลี่ยของยอดรวมเหล่านั้น
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;amount > (...) ต้องคืนค่ากี่ค่า?EXISTS เหนือ IN คืออะไร?FROM ต้องมีอะไรเสมอเพื่อให้ใช้ได้กับทุกที่?