Kodokon kodokon.com

CTE (WITH): ทำให้คิวรีที่ซับซ้อนอ่านง่ายขึ้น

จัดโครงสร้างคิวรีของคุณเป็นขั้นตอนที่มีชื่อด้วย WITH และเชื่อมต่อ CTE หลายตัวเข้าด้วยกันเหมือนไปป์ไลน์ของการแปลงข้อมูล

7 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

คิวรีย่อยที่ซ้อนกันลึกสามชั้นต้องอ่านจากในออกนอก ทั้งอ่านยากและกลับมาแก้ไขไม่ได้เลยในอีกหกเดือนต่อมา CTE (Common Table Expression หรือคำสั่ง WITH) จะพลิกลำดับการอ่าน คุณตั้งชื่อให้แต่ละขั้นตอนกลาง เหมือนกับที่คุณตั้งชื่อฟังก์ชัน และคิวรีจะอ่านจากบนลงล่าง จงโหลดชุดข้อมูลนี้เข้าไปใน sqliteonline.com หรือ sqlite3

SQL
CREATE TABLE payments (
  id INTEGER PRIMARY KEY,
  customer TEXT NOT NULL,
  paid_at TEXT NOT NULL,
  amount REAL NOT NULL
);

INSERT INTO payments (customer, paid_at, amount)
VALUES
  ('alice', '2026-01-10', 120.0),
  ('bruno', '2026-01-22', 80.0),
  ('alice', '2026-02-05', 60.0),
  ('chloe', '2026-02-18', 200.0),
  ('bruno', '2026-03-03', 40.0),
  ('alice', '2026-03-15', 90.0),
  ('chloe', '2026-03-28', 150.0),
  ('bruno', '2026-04-09', 300.0);
ชุดข้อมูลสำหรับบทเรียนนี้

ไวยากรณ์พื้นฐาน: WITH name AS (SELECT ...) ตามด้วยคิวรีหลักที่ใช้ name เหมือนตารางธรรมดา ในที่นี้ เราคำนวณรายได้รายเดือนโดยดึงเดือนออกจากวันที่ด้วย substr (วันที่ใน SQLite เป็นข้อความรูปแบบ ISO 8601 ซึ่งเป็นทางเลือกของเอนจินมากกว่าจะเป็นมาตรฐาน)

SQL
WITH monthly AS (
  SELECT substr(paid_at, 1, 7) AS month,
         SUM(amount) AS revenue
  FROM payments
  GROUP BY month
)
SELECT * FROM monthly ORDER BY month;
CTE อย่างง่าย: หนึ่งขั้นตอนที่มีชื่อและนำกลับมาใช้ซ้ำได้

พลังที่แท้จริงมาจากการ เชื่อมต่อกัน (chaining) คือมี WITH เพียงตัวเดียว มี CTE หลายตัวคั่นด้วยจุลภาค โดยแต่ละตัวสามารถอ่าน CTE ที่ประกาศไว้ก่อนหน้าได้ คุณสร้างไปป์ไลน์ขึ้นมา ได้แก่ รวมกลุ่ม, คำนวณค่าสถิติ, เปรียบเทียบ ในที่นี้ เรามองหาเดือนที่มีรายได้เกินค่าเฉลี่ยรายเดือน (คาดว่า: 2026-03 และ 2026-04 โดยค่าเฉลี่ยคือ 260)

SQL
WITH monthly AS (
  SELECT substr(paid_at, 1, 7) AS month,
         SUM(amount) AS revenue
  FROM payments
  GROUP BY month
),
stats AS (
  SELECT AVG(revenue) AS avg_revenue
  FROM monthly
)
SELECT m.month, m.revenue,
       ROUND(s.avg_revenue, 1) AS avg_all
FROM monthly AS m
CROSS JOIN stats AS s
WHERE m.revenue > s.avg_revenue
ORDER BY m.month;
CTE ที่เชื่อมต่อกัน: stats อ่าน monthly ส่วน SELECT สุดท้ายอ่านทั้งสองตัว

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. คุณจะประกาศ CTE หลายตัวในคิวรีเดียวกันได้อย่างไร?
    • ใส่คำสงวน WITH ก่อน CTE แต่ละตัว
    • ใช้ WITH ตัวเดียว โดยคั่น CTE ด้วยจุลภาค
    • ด้วยการซ้อนมันไว้ในกันและกัน
  2. CTE หนึ่งสามารถอ่าน CTE อีกตัวจาก WITH เดียวกันได้ไหม?
    • ไม่ได้ CTE แต่ละตัวแยกจากกัน
    • ได้ แต่เฉพาะตัวที่ประกาศไว้ก่อนหน้ามันเท่านั้น
    • ได้ ไม่ว่าลำดับใดก็ตาม
  3. ประโยชน์หลักของ CTE เหนือคิวรีย่อยที่ซ้อนกันคืออะไร?
    • มันเร็วกว่าเสมอ
    • มันสร้างตารางถาวรที่นำกลับมาใช้ซ้ำได้
    • มันตั้งชื่อให้แต่ละขั้นตอนและทำให้ลำดับการทำงานอ่านง่ายและทดสอบได้