0Pricing
SQL Academy · บทเรียน

คำค้นย่อยที่สัมพันธ์กัน

คำค้นย่อยที่ขึ้นอยู่กับแถวภายนอก

คำค้นย่อยที่สัมพันธ์กัน เป็นบทเรียน SQL Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน

คิวรีย่อยที่สัมพันธ์กันคืออะไร

คิวรีย่อยที่สัมพันธ์กัน คือคิวรีย่อยที่อ้างอิงคอลัมน์จากคิวรีภายนอกหรือคิวรีที่ครอบอยู่ ซึ่งแตกต่างจากคิวรีย่อยทั่วไปที่ทำงานครั้งเดียวและคืนผลลัพธ์คงที่ คิวรีย่อยที่สัมพันธ์กันจะถูกประเมินผล หนึ่งครั้งต่อทุกแถว ที่คิวรีภายนอกประมวลผล

คุณสมบัตินี้ทำให้เหมาะสำหรับการเปรียบเทียบข้อมูลทีละแถว แต่ก็ใช้ทรัพยากรมากกว่าคิวรีย่อยแบบง่าย

คิวรีย่อยทั่วไปเปรียบเทียบกับคิวรีย่อยที่สัมพันธ์กัน

ความแตกต่างสำคัญคือ คิวรีย่อยทั่วไปไม่มีการอ้างอิงไปยังคิวรีภายนอกและสามารถทำงานได้โดยลำพัง ส่วนคิวรีย่อยที่สัมพันธ์กัน ขึ้นอยู่กับ แถวภายนอก คุณจะเห็นนามแฝงของตารางภายนอกปรากฏอยู่ภายในคิวรีย่อย

ในตัวอย่างด้านล่าง SELECT ภายในอ้างอิง e1.department_id จากคิวรีภายนอก จึงทำให้เกิดความสัมพันธ์ขึ้น

-- Regular subquery (runs once)
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- Correlated subquery (runs once per outer row)
SELECT name, salary, department_id
FROM employees e1
WHERE salary > (
  SELECT AVG(salary)
  FROM employees e2
  WHERE e2.department_id = e1.department_id
);

การเตรียมตารางตัวอย่าง

มาสร้างตารางสองตารางที่จะใช้ตลอดบทเรียนนี้กัน ได้แก่ employees และ departments ตารางเหล่านี้มีข้อมูลสมจริงสำหรับสาธิตคิวรีย่อยที่สัมพันธ์กันในสถานการณ์ต่าง ๆ

CREATE TABLE departments (
  id   INT PRIMARY KEY,
  name VARCHAR(50)
);

CREATE TABLE employees (
  id            INT PRIMARY KEY,
  name          VARCHAR(50),
  department_id INT REFERENCES departments(id),
  salary        NUMERIC(10,2),
  hire_date     DATE
);

INSERT INTO departments VALUES (1,'Engineering'),(2,'Sales'),(3,'HR');

INSERT INTO employees VALUES
  (1,'Alice',  1, 90000, '2020-03-01'),
  (2,'Bob',    1, 75000, '2021-06-15'),
  (3,'Carol',  2, 60000, '2019-01-10'),
  (4,'David',  2, 68000, '2022-09-01'),
  (5,'Eve',    3, 55000, '2020-07-20'),
  (6,'Frank',  1, 95000, '2018-11-05'),
  (7,'Grace',  3, 52000, '2023-02-28'),
  (8,'Henry',  2, 71000, '2021-04-12');

พนักงานที่มีรายได้สูงกว่าค่าเฉลี่ยของแผนก

กรณีใช้งานคลาสสิกของคิวรีย่อยที่สัมพันธ์กันคือ การค้นหาพนักงานทุกคนที่มีเงินเดือนสูงกว่าเงินเดือนเฉลี่ยของแผนกตนเอง คิวรีภายในจะคำนวณเงินเดือนเฉลี่ยของแผนกใหม่ สำหรับแถวพนักงานแต่ละแถว ในคิวรีภายนอก

SELECT e1.name, e1.department_id, e1.salary
FROM employees e1
WHERE e1.salary > (
  SELECT AVG(e2.salary)
  FROM employees e2
  WHERE e2.department_id = e1.department_id
)
ORDER BY e1.department_id, e1.salary DESC;

การใช้คิวรีย่อยที่สัมพันธ์กันใน SELECT

คิวรีย่อยที่สัมพันธ์กันไม่ได้จำกัดอยู่แค่ส่วนคำสั่ง WHERE แต่ยังปรากฏใน รายการ SELECT เพื่อคำนวณค่าสำหรับแต่ละแถวได้ ในที่นี้ เราดึงเงินเดือนของพนักงานแต่ละคนพร้อมเงินเดือนเฉลี่ยของแผนกมาแสดงในคิวรีเดียว

SELECT
  e.name,
  e.salary,
  (
    SELECT ROUND(AVG(e2.salary), 2)
    FROM employees e2
    WHERE e2.department_id = e.department_id
  ) AS dept_avg_salary
FROM employees e
ORDER BY e.department_id, e.name;

การค้นหาพนักงานเงินเดือนสูงสุดของแต่ละแผนก

เราสามารถใช้คิวรีย่อยที่สัมพันธ์กันเพื่อค้นหาพนักงานที่มี เงินเดือนสูงสุดในแต่ละแผนกได้ คิวรีภายในจะค้นหาเงินเดือนสูงสุดของแผนกในแถวปัจจุบัน แล้วคิวรีภายนอกจะเก็บไว้เฉพาะแถวที่มีค่าตรงกัน

SELECT e1.name, e1.department_id, e1.salary
FROM employees e1
WHERE e1.salary = (
  SELECT MAX(e2.salary)
  FROM employees e2
  WHERE e2.department_id = e1.department_id
)
ORDER BY e1.department_id;

EXISTS กับคิวรีย่อยที่สัมพันธ์กัน

ตัวดำเนินการ EXISTS มักใช้คู่กับคิวรีย่อยที่สัมพันธ์กัน โดยจะคืนค่า TRUE หากคิวรีภายในสร้างผลลัพธ์อย่างน้อยหนึ่งแถว ในที่นี้ เราจะแสดงแผนกทั้งหมดที่มีพนักงานอย่างน้อยหนึ่งคนซึ่งเข้าทำงานก่อนปี 2021

SELECT d.name AS department
FROM departments d
WHERE EXISTS (
  SELECT 1
  FROM employees e
  WHERE e.department_id = d.id
    AND e.hire_date < '2021-01-01'
);

NOT EXISTS กับคิวรีย่อยที่สัมพันธ์กัน

NOT EXISTS มีความหมายตรงข้าม โดยจะคืนค่า TRUE เมื่อคิวรีย่อยที่สัมพันธ์กันไม่พบ แถวที่ตรงกัน เหมาะสำหรับค้นหาระเบียนแม่ที่ไม่มีระเบียนลูก เช่น แผนกที่ไม่มีพนักงาน

SELECT d.name AS department_without_employees
FROM departments d
WHERE NOT EXISTS (
  SELECT 1
  FROM employees e
  WHERE e.department_id = d.id
);

คิวรีย่อยที่สัมพันธ์กันใน UPDATE

คิวรีย่อยที่สัมพันธ์กันยังใช้ภายในคำสั่ง UPDATE ได้ด้วย ตัวอย่างต่อไปนี้จะเพิ่มคอลัมน์ dept_avg แล้วใช้คิวรีย่อยที่สัมพันธ์กันเติมเงินเดือนเฉลี่ยของแผนกให้กับพนักงานแต่ละคน

ALTER TABLE employees ADD COLUMN dept_avg NUMERIC(10,2);

UPDATE employees e1
SET dept_avg = (
  SELECT ROUND(AVG(e2.salary), 2)
  FROM employees e2
  WHERE e2.department_id = e1.department_id
);

SELECT name, salary, dept_avg FROM employees ORDER BY department_id, name;

คิวรีย่อยที่สัมพันธ์กันใน DELETE

คุณยังสามารถใช้คิวรีย่อยที่สัมพันธ์กันในคำสั่ง DELETE เพื่อลบแถวตามข้อมูลจากตารางที่เกี่ยวข้องได้ คิวรีด้านล่างจะลบพนักงานที่มีเงินเดือนต่ำกว่า 60% ของเงินเดือนเฉลี่ยในแผนก ซึ่งเป็นรูปแบบหนึ่งของการล้างข้อมูล

DELETE FROM employees e1
WHERE e1.salary < (
  SELECT AVG(e2.salary) * 0.60
  FROM employees e2
  WHERE e2.department_id = e1.department_id
);

SELECT name, salary, department_id FROM employees ORDER BY department_id;

เคล็ดลับด้านประสิทธิภาพ: คิวรีย่อยที่สัมพันธ์กันเปรียบเทียบกับ JOIN

คิวรีย่อยที่สัมพันธ์กันจะทำงานหนึ่งครั้งต่อแถวภายนอก จึงอาจช้าเมื่อตารางมีขนาดใหญ่ คิวรีย่อยที่สัมพันธ์กันจำนวนมากสามารถเขียนใหม่เป็น JOIN กับตารางที่สร้างจากคิวรีหรือ CTE เพื่อเพิ่มประสิทธิภาพได้ ควรทำความเข้าใจทั้งสองรูปแบบ แล้วเลือกใช้ตามความอ่านง่ายและแผนการทำงาน

-- Correlated version (potentially slower)
SELECT e1.name, e1.salary
FROM employees e1
WHERE e1.salary > (
  SELECT AVG(e2.salary)
  FROM employees e2
  WHERE e2.department_id = e1.department_id
);

-- Equivalent JOIN + derived table (often faster)
SELECT e.name, e.salary
FROM employees e
JOIN (
  SELECT department_id, AVG(salary) AS avg_sal
  FROM employees
  GROUP BY department_id
) dept_avg ON dept_avg.department_id = e.department_id
WHERE e.salary > dept_avg.avg_sal;

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับคิวรีย่อยที่สัมพันธ์กัน

สรุป: คิวรีย่อยที่สัมพันธ์กัน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า คิวรีย่อยที่สัมพันธ์กัน อ้างอิงคอลัมน์จากคิวรีภายนอกและถูกประเมินผลใหม่สำหรับแต่ละแถวภายนอก ประเด็นสำคัญ:

  • คิวรีย่อยเหล่านี้ปรากฏได้ใน SELECT, WHERE, UPDATE และ DELETE
  • EXISTS / NOT EXISTS ใช้คู่กับคิวรีย่อยที่สัมพันธ์กันได้อย่างเป็นธรรมชาติ เพื่อทดสอบว่ามีแถวที่เกี่ยวข้องหรือไม่
  • คิวรีย่อยเหล่านี้สื่อความหมายได้ดี แต่อาจทำงานช้า ควรพิจารณาเขียนใหม่เป็น JOIN เมื่อประสิทธิภาพมีความสำคัญ
  • นามแฝงของตารางภายนอกภายในคิวรีย่อยคือสิ่งที่ทำให้เกิดความสัมพันธ์

คำถามที่พบบ่อย

บทเรียน “คำค้นย่อยที่สัมพันธ์กัน” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “คำค้นย่อยที่สัมพันธ์กัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “คำค้นย่อยที่สัมพันธ์กัน”

คำค้นย่อยที่ขึ้นอยู่กับแถวภายนอก คุณปฏิบัติ SQL Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “คำค้นย่อยที่สัมพันธ์กัน” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน SQL Academy นี้ได้ไหม

ได้ บทเรียน SQL Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. คำค้นย่อยที่สัมพันธ์กัน
  2. EXISTS และ NOT EXISTS
  3. IN เทียบกับ ANY เทียบกับ ALL
  4. ประสิทธิภาพของ EXISTS เทียบกับ JOIN
← กลับไปที่ SQL Academy