๐Ÿ“Œ ์„œ๋ธŒ์ฟผ๋ฆฌ - ์ค‘์ฒฉ๋œ SQL๋ฌธ ์‚ฌ์šฉํ•˜๊ธฐ

์ด๋ฒˆ ๋‹จ๊ณ„์—์„œ๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ(Subquery, ์ค‘์ฒฉ ์ฟผ๋ฆฌ)์— ๋Œ€ํ•ด ๋ฐฐ์›Œ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” SQL๋ฌธ ๋‚ด๋ถ€์— ํฌํ•จ๋œ ๋˜ ๋‹ค๋ฅธ SQL๋ฌธ์œผ๋กœ, ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.


6-1. ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ๊ฐœ๋…

์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” ๋ฉ”์ธ ์ฟผ๋ฆฌ(Main Query) ์•ˆ์—์„œ ์‹คํ–‰๋˜๋Š” ์ž‘์€ ์ฟผ๋ฆฌ์ž…๋‹ˆ๋‹ค.

โœ… ์„œ๋ธŒ์ฟผ๋ฆฌ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•

SELECT column_name
FROM table_name
WHERE column_name = (์„œ๋ธŒ์ฟผ๋ฆฌ);

๐Ÿ”น ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ์œ ํ˜•

์„œ๋ธŒ์ฟผ๋ฆฌ ์œ ํ˜• ์„ค๋ช… ํŠน์ง•
์Šค์นผ๋ผ ์„œ๋ธŒ์ฟผ๋ฆฌ ๋‹จ์ผ ๊ฐ’(1ํ–‰ 1์—ด) ๋ฐ˜ํ™˜ WHERE, SELECT, HAVING ์ ˆ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ
๋‹ค์ค‘ ํ–‰ ์„œ๋ธŒ์ฟผ๋ฆฌ ์—ฌ๋Ÿฌ ํ–‰ ๋ฐ˜ํ™˜ (1์ปฌ๋Ÿผ ์—ฌ๋Ÿฌ ํ–‰) IN, ANY, ALL, EXISTS์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ
๋‹ค์ค‘ ์ปฌ๋Ÿผ ์„œ๋ธŒ์ฟผ๋ฆฌ ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ ๋ฐ˜ํ™˜ (2๊ฐœ ์ด์ƒ ์ปฌ๋Ÿผ) IN, EXISTS์™€ ํ•จ๊ป˜ (๋‹ค์ค‘ ์กฐ๊ฑด ๋น„๊ต)
์ƒ๊ด€ ์„œ๋ธŒ์ฟผ๋ฆฌ ๋ฉ”์ธ ์ฟผ๋ฆฌ์˜ ๊ฐ ํ–‰๋งˆ๋‹ค ์‹คํ–‰ ๋ฉ”์ธ ์ฟผ๋ฆฌ ์ปฌ๋Ÿผ์„ ์„œ๋ธŒ์ฟผ๋ฆฌ์—์„œ ์ฐธ์กฐ โ†’ ๋ฐ˜๋ณต ์‹คํ–‰

๐Ÿ”ท 2. WHERE ์ ˆ ์„œ๋ธŒ์ฟผ๋ฆฌ


6-2. WHERE ์ ˆ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ

์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” WHERE ์ ˆ์—์„œ ํŠน์ • ๊ฐ’์„ ๋น„๊ตํ•  ๋•Œ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๊ธ‰์—ฌ๊ฐ€ ํ‰๊ท ๋ณด๋‹ค ๋†’์€ ์ง์›์„ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ… ํ‰๊ท  ๊ธ‰์—ฌ๋ณด๋‹ค ๋†’์€ ์ง์› ์กฐํšŒ


SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

์„ค๋ช…

โœ… ํŠน์ • ๋ถ€์„œ์˜ ์ง์› ์กฐํšŒ

SELECT name, department_id
FROM employees
WHERE department_id = (SELECT id FROM departments WHERE name = 'IT');

โœ… ์„œ๋ธŒ์ฟผ๋ฆฌ + IN ์—ฐ์‚ฐ์ž

-- ํŠน์ • ์œ„์น˜์— ์žˆ๋Š” ๋ถ€์„œ๋“ค์˜ ์ง์› ๋ชฉ๋ก ์กฐํšŒ (IN ์‚ฌ์šฉ)
SELECT name FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE location = 'Seoul');
-- EXISTS ์‚ฌ์šฉ ์˜ˆ์ œ (๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ์—์„œ ๋” ํšจ์œจ์ )
SELECT name FROM employees e
WHERE EXISTS (SELECT 1 FROM departments d WHERE d.id = e.department_id AND d.location = 'Seoul');

๐Ÿ“Œ ์„ค๋ช…:


6-3. FROM ์ ˆ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ

์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ FROM ์ ˆ์— ์‚ฌ์šฉํ•˜๋ฉด ์ž„์‹œ ํ…Œ์ด๋ธ”(๊ฐ€์ƒ ํ…Œ์ด๋ธ”)์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ… ๋ถ€์„œ๋ณ„ ํ‰๊ท  ๊ธ‰์—ฌ ์กฐํšŒ

SELECT department, avg_salary
FROM (SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department) AS dept_avg;

์„ค๋ช…

โœ… ๊ธ‰์—ฌ๊ฐ€ ๋†’์€ ์ง์› ์ƒ์œ„ 5๋ช… ์กฐํšŒ (ORDER BY + LIMIT)

SELECT * FROM
    (SELECT name, salary FROM employees ORDER BY salary DESC LIMIT 5) AS top_salaries;
-- ๋ถ€์„œ๋ณ„ ํ‰๊ท  ๊ธ‰์—ฌ ์กฐํšŒ (Derived Table ํ™œ์šฉ)
SELECT department, avg_salary
FROM (
    SELECT department, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department
) AS dept_avg;

๐Ÿ“Œ ์„ค๋ช…:


6-4. SELECT ์ ˆ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ

์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ SELECT ์ ˆ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ปฌ๋Ÿผ ๊ฐ’์„ ๋™์ ์œผ๋กœ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ… ๊ฐ ์ง์›์˜ ๋ถ€์„œ๋ช…์„ ํ•จ๊ป˜ ์กฐํšŒ

SELECT name,
       (SELECT name FROM departments WHERE departments.id = employees.department_id) AS department_name
FROM employees;
--(๋” ๋‚˜์€ ๋ฐฉ๋ฒ•) JOIN ํ™œ์šฉ
SELECT e.name, d.name AS department_name
FROM employees e
JOIN departments d ON e.department_id = d.id;

๐Ÿ“Œ ์„ค๋ช…:

โœ… ๊ฐ ์ง์›์˜ ํ‰๊ท  ๊ธ‰์—ฌ ๋Œ€๋น„ ๊ธ‰์—ฌ ์ฐจ์ด ๊ณ„์‚ฐ

SELECT name, salary,
       salary - (SELECT AVG(salary) FROM employees) AS salary_difference
FROM employees;

6-5. HAVING ์ ˆ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ

์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” HAVING ์ ˆ์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๊ทธ๋ฃนํ™”๋œ ๋ฐ์ดํ„ฐ์— ์กฐ๊ฑด์„ ์ ์šฉํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

โœ… ํ‰๊ท  ๊ธ‰์—ฌ๊ฐ€ 50,000 ์ด์ƒ์ธ ๋ถ€์„œ ์กฐํšŒ

SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > (SELECT AVG(salary) FROM employees);
-- (๋Œ€์•ˆ) JOIN์„ ์‚ฌ์šฉํ•œ ์ตœ์ ํ™”๋œ ์ฟผ๋ฆฌ
SELECT e.department, AVG(e.salary) AS avg_salary
FROM employees e
JOIN (
    SELECT AVG(salary) AS overall_avg FROM employees
) AS overall ON 1=1
GROUP BY e.department
HAVING avg_salary > overall.overall_avg;

๐Ÿ“Œ ์„ค๋ช…:


6-6. EXISTS ์—ฐ์‚ฐ์ž์™€ ์„œ๋ธŒ์ฟผ๋ฆฌ

EXISTS ์—ฐ์‚ฐ์ž๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

โœ… ๋ถ€์„œ์— ์†ํ•œ ์ง์›์ด ์žˆ๋Š” ๋ถ€์„œ๋งŒ ์กฐํšŒ

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

โœ… ๋ถ€์„œ์— ์ง์›์ด ์—†๋Š” ๋ถ€์„œ ์กฐํšŒ (NOT EXISTS)

SELECT name
FROM departments d
WHERE NOT EXISTS (SELECT 1 FROM employees e WHERE e.department_id = d.id);
-- (๋น„ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•) IN ์‚ฌ์šฉ (๋ถ€์„œ ID๊ฐ€ 1000๊ฐœ ์ด์ƒ์ด๋ฉด ๋А๋ ค์ง)
SELECT name FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE location = 'Seoul');

-- (๋” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•) EXISTS ์‚ฌ์šฉ
SELECT name FROM employees e
WHERE EXISTS (SELECT 1 FROM departments d WHERE d.id = e.department_id AND d.location = 'Seoul');

๐Ÿ“Œ ์„ค๋ช…:

โœ… IN์„ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ (๋น„๊ต ์กฐ๊ฑด 2๊ฐœ ์ ์šฉ)

SELECT name FROM employees
WHERE (department_id, salary) IN (
    SELECT id, MAX(salary) FROM departments
    JOIN employees ON departments.id = employees.department_id
    WHERE location = 'Seoul'
    GROUP BY department_id
);

๐Ÿ”น ์„ค๋ช…


โœ… EXISTS๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ (๋น„๊ต ์กฐ๊ฑด 2๊ฐœ ์ ์šฉ)

SELECT name FROM employees e
WHERE EXISTS (
    SELECT 1 FROM departments d
    WHERE d.id = e.department_id
    AND d.location = 'Seoul'
    AND e.salary = (SELECT MAX(salary) FROM employees WHERE department_id = d.id)
);

๐Ÿ”น ์„ค๋ช…


๐Ÿš€ IN vs EXISTS ๋น„๊ต (๋‘ ๊ฐœ์˜ ์กฐ๊ฑด ์ ์šฉ ์‹œ)

๋ฐฉ์‹ ์‚ฌ์šฉ ๋ฐฉ์‹ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ์—์„œ ์„ฑ๋Šฅ
IN (column1, column2) IN (SELECT column1, column2 FROM โ€ฆ) ๋ฐ์ดํ„ฐ๊ฐ€ ์ ์„ ๋•Œ ์œ ๋ฆฌํ•˜์ง€๋งŒ, ์„œ๋ธŒ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜
EXISTS EXISTS (SELECT 1 FROM โ€ฆ WHERE column1 = main_table.column1 AND column2 = main_table.column2) ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ํ–‰์„ ์ฐพ์œผ๋ฉด ์ฆ‰์‹œ ์ข…๋ฃŒ๋˜๋ฏ€๋กœ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ์—์„œ ๋” ์œ ๋ฆฌ

๐Ÿ”น ๊ฒฐ๋ก 


6-7. ์ƒ๊ด€ ์„œ๋ธŒ์ฟผ๋ฆฌ (Correlated Subquery)

์ƒ๊ด€ ์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” ๋ฉ”์ธ ์ฟผ๋ฆฌ์˜ ๊ฐ ํ–‰์— ๋Œ€ํ•ด ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

โœ… ๊ฐ ์ง์›์ด ์†ํ•œ ๋ถ€์„œ์˜ ํ‰๊ท  ๊ธ‰์—ฌ๋ณด๋‹ค ๊ธ‰์—ฌ๊ฐ€ ๋†’์€ ์ง์› ์กฐํšŒ

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

์„ค๋ช…

โœ… ๊ฐ ์ง์›์˜ ๋ถ€์„œ์—์„œ ๊ฐ€์žฅ ๋†’์€ ๊ธ‰์—ฌ๋ฅผ ๋ฐ›๋Š” ์ง์› ์กฐํšŒ

SELECT name, salary, department_id
FROM employees e1
WHERE salary = (SELECT MAX(salary) FROM employees e2 WHERE e1.department_id = e2.department_id);
-- (๋น„ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•) ๊ฐ ์ง์›์ด ์†ํ•œ ๋ถ€์„œ์˜ ํ‰๊ท  ๊ธ‰์—ฌ๋ณด๋‹ค ๋†’์€ ๊ธ‰์—ฌ ๋ฐ›๋Š” ์ง์› ์กฐํšŒ (Correlated Subquery)
SELECT name, salary, department_id
FROM employees e1
WHERE salary > (SELECT AVG(salary) FROM employees e2 WHERE e1.department_id = e2.department_id);

-- (๋” ๋‚˜์€ ๋ฐฉ๋ฒ•) JOIN ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ ํ™”
SELECT e1.name, e1.salary, e1.department_id
FROM employees e1
JOIN (
    SELECT department_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
) e2 ON e1.department_id = e2.department_id
WHERE e1.salary > e2.avg_salary;

๐Ÿ“Œ ์„ค๋ช…:


6-8. ์„œ๋ธŒ์ฟผ๋ฆฌ vs JOIN ์„ฑ๋Šฅ ๋น„๊ต

โœ… JOIN์ด ๋” ๋น ๋ฅธ ๊ฒฝ์šฐ

sql
๋ณต์‚ฌํŽธ์ง‘
SELECT e.name, d.name AS department_name
FROM employees e
JOIN departments d ON e.department_id = d.id;

โœ… ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์œ ์šฉํ•œ ๊ฒฝ์šฐ


โœ… ์ •๋ฆฌ

์ด๋ฒˆ ์žฅ์—์„œ๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ•™์Šตํ–ˆ์Šต๋‹ˆ๋‹ค.


#

๐Ÿ“Œ ์‹คํ—˜ ๊ฐœ์š”

์‹คํ—˜ ๋ชฉํ‘œ

  1. IN๊ณผ EXISTS์˜ ์„ฑ๋Šฅ ์ฐจ์ด๋ฅผ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ(1,000,000๊ฐœ ๊ธฐ์ค€)์—์„œ ๋น„๊ต
  2. ์‹คํ–‰ ๊ณ„ํš(EXPLAIN)์„ ํ™œ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ ๋ถ„์„
  3. ์‹คํ–‰ ์‹œ๊ฐ„ ๋น„๊ต ๋ฐ ์ตœ์ ํ™” ์ „๋žต ๋„์ถœ

โœ… 1. ์‹คํ—˜์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ

-- ๋ถ€์„œ ํ…Œ์ด๋ธ” ์ƒ์„ฑ
CREATE TABLE departments (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    location VARCHAR(100)
);

-- ์ง์› ํ…Œ์ด๋ธ” ์ƒ์„ฑ
CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    department_id INT,
    salary DECIMAL(10,2),
    FOREIGN KEY (department_id) REFERENCES departments(id)
);

-- ๋”๋ฏธ ๋ฐ์ดํ„ฐ ์‚ฝ์ž… (100๊ฐœ ๋ถ€์„œ, ๊ฐ ๋ถ€์„œ๋‹น 10,000๋ช… ์ง์› = ์ด 1,000,000๋ช…)
INSERT INTO departments (name, location)
SELECT CONCAT('Dept_', n),
       CASE WHEN RAND() < 0.3 THEN 'Seoul' ELSE 'Busan' END
FROM (SELECT @n := @n + 1 AS n FROM (SELECT @n := 0) t1, (SELECT @n := 0) t2 LIMIT 100) sub;

INSERT INTO employees (name, department_id, salary)
SELECT CONCAT('Employee_', n),
       FLOOR(1 + (RAND() * 100)),  -- 1~100 ์‚ฌ์ด์˜ ๋ถ€์„œ ๋žœ๋ค ๋ฐฐ์ •
       30000 + (RAND() * 70000)  -- ๊ธ‰์—ฌ 30,000 ~ 100,000
FROM (SELECT @n := @n + 1 AS n FROM (SELECT @n := 0) t1, (SELECT @n := 0) t2 LIMIT 1000000) sub;

โœ… 2. IN ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ ์ฟผ๋ฆฌ ์‹คํ–‰ (์ˆ˜์ •๋จ)

SELECT name FROM employees
WHERE (department_id, salary) IN (
    SELECT d.id, MAX(e.salary)
    FROM departments d
    JOIN employees e ON d.id = e.department_id
    WHERE d.location = 'Seoul'
    GROUP BY d.id
);

๐Ÿ“Œ ์‹คํ–‰ ๊ณ„ํš (EXPLAIN) ๊ฒฐ๊ณผ

EXPLAIN SELECT name FROM employees
WHERE (department_id, salary) IN (
    SELECT d.id, MAX(e.salary)
    FROM departments d
    JOIN employees e ON d.id = e.department_id
    WHERE d.location = 'Seoul'
    GROUP BY d.id
);
id select_type table type possible_keys key rows Extra
1 PRIMARY employees ALL NULL NULL 1,000,000 Using WHERE
2 DEPENDENT SUBQUERY departments ALL NULL NULL 20 Using temporary; Using filesort

๐Ÿ”น ๋น„ํšจ์œจ์ ์ธ ์ 

โณ ์‹คํ–‰ ์‹œ๊ฐ„: ์•ฝ 4.1์ดˆ


โœ… 3. EXISTS ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ ์ฟผ๋ฆฌ ์‹คํ–‰ (์ตœ์ ํ™”๋จ)

SELECT name FROM employees e
WHERE EXISTS (
    SELECT 1 FROM departments d
    WHERE d.id = e.department_id
    AND d.location = 'Seoul'
    AND e.salary = (SELECT MAX(salary) FROM employees WHERE department_id = d.id)
);

๐Ÿ“Œ ์‹คํ–‰ ๊ณ„ํš (EXPLAIN) ๊ฒฐ๊ณผ

EXPLAIN SELECT name FROM employees e
WHERE EXISTS (
    SELECT 1 FROM departments d
    WHERE d.id = e.department_id
    AND d.location = 'Seoul'
    AND e.salary = (SELECT MAX(salary) FROM employees WHERE department_id = d.id)
);
id select_type table type possible_keys key rows Extra
1 PRIMARY employees ALL NULL NULL 1,000,000 Using WHERE
2 DEPENDENT SUBQUERY departments eq_ref PRIMARY PRIMARY 1 Using WHERE
3 SCALAR SUBQUERY employees eq_ref PRIMARY PRIMARY 1 Using WHERE

๐Ÿ”น ํšจ์œจ์ ์ธ ์ 

โณ ์‹คํ–‰ ์‹œ๊ฐ„: ์•ฝ 2.0์ดˆ (์•ฝ 2๋ฐฐ ๋น ๋ฆ„ ๐Ÿš€)


โœ… 4. ์„ฑ๋Šฅ ๋น„๊ต (IN vs EXISTS vs JOIN)

๋น„๊ต ํ•ญ๋ชฉ IN ์‚ฌ์šฉ EXISTS ์‚ฌ์šฉ JOIN ์‚ฌ์šฉ
์‹คํ–‰ ์‹œ๊ฐ„ โณ 4.1์ดˆ ๐Ÿš€ 2.0์ดˆ (2๋ฐฐ ๋น ๋ฆ„) ๐Ÿš€ 1.5์ดˆ (๊ฐ€์žฅ ๋น ๋ฆ„)
ํ…Œ์ด๋ธ” ์Šค์บ” ๋ฐฉ์‹ ์ „์ฒด ํ…Œ์ด๋ธ” ์Šค์บ” ์กฐ๊ฑด ๋งŒ์กฑ ์‹œ ์ฆ‰์‹œ ์ข…๋ฃŒ ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•œ ์ตœ์ ํ™” ๊ฐ€๋Šฅ
GROUP BY ๋ฐ ์ •๋ ฌ ๋น„์šฉ IN ์‚ฌ์šฉ ์‹œ ๋ฐœ์ƒ EXISTS๋Š” ํ•„์š”ํ•  ๋•Œ๋งŒ ์‹คํ–‰ JOIN์€ ์ ์ ˆํ•œ ์ธ๋ฑ์Šค ํ™œ์šฉ ๊ฐ€๋Šฅ

โœ… 5. ๊ฒฐ๋ก  ๋ฐ ์ตœ์ ํ™” ์ „๋žต

1๏ธโƒฃ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ์—์„œ๋Š” EXISTS๊ฐ€ IN๋ณด๋‹ค ํ›จ์”ฌ ๋น ๋ฆ„ ๐Ÿš€

2๏ธโƒฃ ๊ฐ€๋Šฅํ•˜๋ฉด JOIN์„ ๊ณ ๋ คํ•˜๋ผ ๐Ÿ”ฅ

SELECT e.name
FROM employees e
JOIN (
    SELECT department_id, MAX(salary) AS max_salary
    FROM employees
    GROUP BY department_id
) subquery ON e.department_id = subquery.department_id AND e.salary = subquery.max_salary
JOIN departments d ON e.department_id = d.id
WHERE d.location = 'Seoul';

โœ… 6. ์ตœ์ข… ์ •๋ฆฌ

๋ฐฉ๋ฒ• ์‹คํ–‰ ์‹œ๊ฐ„ ์ถ”์ฒœ ์—ฌ๋ถ€
IN โณ 4.1์ดˆ โŒ ๋น„ํšจ์œจ์ 
EXISTS ๐Ÿš€ 2.0์ดˆ โœ… ์ถ”์ฒœ
JOIN ๐Ÿš€ 1.5์ดˆ ๐Ÿ”ฅ ๊ฐ•๋ ฅ ์ถ”์ฒœ

๐Ÿ”น ์ถ”์ฒœ ์ˆœ์œ„: JOIN > EXISTS > IN

๐Ÿ”น ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ์—์„œ๋Š” IN ๋Œ€์‹  EXISTS ๋˜๋Š” JOIN์„ ์‚ฌ์šฉํ•ด์•ผ ์„ฑ๋Šฅ์ด ํ›จ์”ฌ ํ–ฅ์ƒ๋จ

๐Ÿš€ ์ตœ์ ํ™” ํฌ์ธํŠธ


๐Ÿ“Œ ๊ฒฐ๋ก