노션정리
서브쿼리 및 관련 SQL 개념 정리
1. 서브쿼리 유형 요약
| 구분 | 설명 | 사용 위치 | 특징 |
|---|
| 단일행 서브쿼리 | 하나의 행을 반환 | WHERE, HAVING | =, >, < 등과 함께 사용 |
| 다중행 서브쿼리 | 여러 행을 반환 | WHERE, HAVING | IN, ANY, ALL, EXISTS |
| 상호연관 서브쿼리 | 외부 쿼리와 연동되어 반복 실행 | WHERE, SELECT | 외부의 각 행마다 실행 |
| 스칼라 서브쿼리 | 하나의 값 반환 | SELECT, WHERE 등 | 컬럼처럼 활용 |
| 인라인 뷰 | FROM 절에 서브쿼리 사용 | FROM (SELECT …) | 임시 테이블 역할 |
| 계층형 쿼리 | 트리 구조 조회 | START WITH, CONNECT BY | 계층 수준(LEVEL) 활용 |
| Top-N 쿼리 | 상위/하위 N건 조회 | ROWNUM, ROW_NUMBER, FETCH 등 | 정렬 후 추출 |
| CTE (WITH 절) | 공통 테이블 표현식 | 쿼리 전체 구조 상단 | 재사용성과 가독성 향상 |
2. 주요 SQL 예제
단일행 서브쿼리
SELECT first_name, job_id, hire_date
FROM employees
WHERE job_id = (SELECT job_id FROM employees WHERE employee_id = 103);
다중행 서브쿼리
SELECT first_name, salary
FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE first_name = 'David');
SELECT first_name, salary
FROM employees
WHERE salary IN (SELECT salary FROM employees WHERE first_name = 'David');
EXISTS
SELECT first_name, salary
FROM employees e
WHERE EXISTS (
SELECT * FROM departments d
WHERE d.manager_id = e.employee_id
);
상호연관 서브쿼리
SELECT first_name, salary
FROM employees a
WHERE salary > (
SELECT AVG(salary)
FROM employees b
WHERE b.department_id = a.department_id
);
스칼라 서브쿼리
SELECT first_name,
(SELECT department_name
FROM departments d
WHERE d.department_id = e.department_id) AS department_name
FROM employees e;
인라인 뷰
SELECT row_number, first_name, salary
FROM (
SELECT first_name, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_number
FROM employees
)
WHERE row_number BETWEEN 1 AND 10;
FETCH 사용 (Oracle 12c+)
SELECT first_name, salary
FROM employees
ORDER BY salary DESC
OFFSET 10 ROWS
FETCH FIRST 5 ROWS ONLY;
계층형 쿼리
SELECT
employee_id,
LPAD(' ', 3 * (LEVEL - 1)) || first_name || ' ' || last_name AS full_name,
LEVEL
FROM
employees
START WITH
manager_id IS NULL
CONNECT BY
PRIOR employee_id = manager_id;
CTE (공통 테이블 표현식)
WITH dept_avg_salary AS (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
)
SELECT e.first_name, e.salary, d.avg_salary
FROM employees e
JOIN dept_avg_salary d ON e.department_id = d.department_id
WHERE e.salary > d.avg_salary;
3. 서브쿼리 vs 조인 비교
| 상황 | 서브쿼리 | 조인 |
|---|
| 단일 값 비교 | 간단하고 직관적 | 불필요 |
| 다수 테이블 결합 | 복잡해질 수 있음 | 효율적 |
| 재사용 가능성 | 불리 | 유리 |
| 성능 측면 | 경우에 따라 느릴 수 있음 | 인덱스와 최적화에 유리 |
| 가독성 | 간단한 경우 유리 | 복잡한 로직에 유리 |
1. CREATE TABLE AS SELECT (CTAS)
- 기존 테이블 구조 및 데이터를 기반으로 새 테이블을 생성
- 컬럼, 데이터 타입, 제약조건 중 일부는 계승되지 않음
CREATE TABLE new_table AS
SELECT employee_id, first_name, salary
FROM employees
WHERE department_id = 90;
2. INSERT
단일 행 삽입
INSERT INTO departments (department_id, department_name, manager_id, location_id)
VALUES (280, 'Data Analytics', NULL, 1700);
다른 테이블로부터 여러 행 삽입 (서브쿼리 사용)
INSERT INTO managers (employee_id, first_name, job_id, salary, hire_date)
SELECT employee_id, first_name, job_id, salary, hire_date
FROM employees
WHERE job_id LIKE '%MAN';
3. UPDATE
기본 사용법
UPDATE employees
SET salary = salary * 1.1
WHERE employee_id = 103;
서브쿼리를 이용한 다중 열 갱신
UPDATE employees
SET (job_id, salary, manager_id) = (
SELECT job_id, salary, manager_id
FROM employees
WHERE employee_id = 108
)
WHERE employee_id = 109;
※ 단, 위 문법은 Oracle에서만 가능하며, SET에 괄호 묶인 컬럼 리스트와 반환되는 서브쿼리 열 순서가 일치해야 합니다.
4. DELETE
단순 조건 기반 삭제
DELETE FROM employees
WHERE employee_id = 104;
서브쿼리를 이용한 조건 삭제
DELETE FROM employees
WHERE department_id = (
SELECT department_id
FROM departments
WHERE department_name = 'Shipping'
);
※ 서브쿼리가 다중행 반환 가능성이 있을 땐 IN 사용 권장
5. MERGE
- Oracle 전용 DML로, 조건에 따라
INSERT, UPDATE, 또는 아무 작업도 수행하지 않음
- 주로 데이터 동기화, 비교 병합 처리에 유용
MERGE INTO target_table t
USING source_table s
ON (t.employee_id = s.employee_id)
WHEN MATCHED THEN
UPDATE SET t.salary = s.salary, t.job_id = s.job_id
WHEN NOT MATCHED THEN
INSERT (employee_id, first_name, job_id, salary, hire_date)
VALUES (s.employee_id, s.first_name, s.job_id, s.salary, s.hire_date);
부가 팁: MERGE 문 사용 시 고려사항
| 항목 | 설명 |
|---|
ON 조건 | 기준이 되는 Key 또는 비교 기준 정의 |
MATCHED | 기준이 일치할 경우 수행 (UPDATE) |
NOT MATCHED | 기준이 없을 경우 수행 (INSERT) |
| 제약 조건 | PK 또는 Unique Key로 비교하는 것이 일반적 |
1. Unconditional Multiple Insert (INSERT ALL)
개념
- 조건 없이 SELECT로 조회된 모든 결과를 여러 테이블에 모두 삽입
- 각
INTO 절은 항상 실행
예시
INSERT ALL
INTO emp_backup1 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
INTO emp_backup2 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
SELECT employee_id, first_name, salary
FROM employees;
2. Conditional Multiple Insert (INSERT ALL ... WHEN)
개념
- 여러
WHEN 조건을 지정하여 SELECT 결과를 각각의 조건에 맞는 테이블에 분기 삽입
- 여러
WHEN 절이 동시에 만족하면 모두 실행 (중복 삽입 가능성 있음)
예시
INSERT ALL
WHEN department_id = 10 THEN
INTO emp_10 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
WHEN department_id = 20 THEN
INTO emp_20 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
WHEN department_id = 30 THEN
INTO emp_30 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
SELECT employee_id, first_name, salary, department_id
FROM employees;
3. Conditional Insert with Priority (INSERT FIRST ... WHEN)
개념
INSERT FIRST는 조건을 위에서부터 차례대로 검사
- 가장 먼저 만족하는 조건만 실행, 이후 조건은 무시
- 조건이 서로 겹치거나 범위 조건일 때 유리
예시
INSERT FIRST
WHEN salary <= 5000 THEN
INTO emp_sal5000 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
WHEN salary <= 10000 THEN
INTO emp_sal10000 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
WHEN salary <= 15000 THEN
INTO emp_sal15000 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
WHEN salary <= 20000 THEN
INTO emp_sal20000 (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
ELSE
INTO emp_sal_others (employee_id, first_name, salary)
VALUES (employee_id, first_name, salary)
SELECT employee_id, first_name, salary
FROM employees;
비교 요약
| 구분 | 실행 방식 | 사용 목적 |
|---|
INSERT ALL | 모든 대상 테이블에 삽입 | 백업, 다중복사 |
INSERT ALL WHEN | 조건에 따라 여러 군데 삽입 가능 | 값 분기 저장 |
INSERT FIRST WHEN | 조건 중 첫 번째만 실행 | 범위 기반 분류 |
1. 트랜잭션 (Transaction)
- 논리적인 작업의 단위
- 여러 SQL 명령을 하나의 작업 단위로 처리
- 완전하게 수행되거나 전혀 수행되지 않아야 함 (Atomicity)
트랜잭션 종료 방식
| 종료 방법 | 설명 |
|---|
COMMIT | 변경 사항을 영구 반영 |
ROLLBACK | 변경 사항을 취소 |
| DDL / DCL 실행 | 자동으로 커밋 발생 (암묵적 커밋) |
2. 트랜잭션 흐름 예시 (텍스트 그림)
[BEGIN]
├── DML(1): DELETE FROM emps WHERE department_id = 20;
├── SAVEPOINT delete_20
├── DML(2): DELETE FROM emps WHERE department_id = 30;
├── ROLLBACK TO delete_20 -- 30번 삭제 취소, 20번 삭제는 유지
└── COMMIT -- 전체 확정 저장
[END]
예시 코드
DELETE FROM emps WHERE department_id = 20;
SAVEPOINT delete_20;
DELETE FROM emps WHERE department_id = 30;
ROLLBACK TO delete_20;
COMMIT;
3. 세이브포인트 (SAVEPOINT)
- 트랜잭션 내에서 부분 롤백 지점을 설정
- 이후 특정 시점까지 롤백 가능
SAVEPOINT save1;
...
ROLLBACK TO save1;
4. 자동 커밋 (Auto Commit)
- Oracle에서는 기본적으로 자동 커밋이 비활성화되어 있음
- 수동으로
COMMIT 해야만 변경 사항이 저장됨
오토커밋 설정 (SQL*Plus 기준)
SET AUTOCOMMIT ON;
SET AUTOCOMMIT OFF;
자동 커밋은 실수로 인한 데이터 손실 위험이 높기 때문에 권장되지 않음
5. 데이터 잠금 (LOCK)
개념
- 여러 사용자의 동시 작업에서 일관된 읽기/쓰기 보장
- DML 수행 시 자동으로 락이 걸리며, 명시적으로도 요청 가능
테이블 락
LOCK TABLE employees IN EXCLUSIVE MODE;
- EXCLUSIVE MODE: 다른 사용자의 읽기/쓰기 모두 차단
주요 테이블 락 모드
| 모드 | 설명 |
|---|
ROW SHARE | 가장 낮은 수준의 잠금 (다른 사용자의 DML 허용) |
ROW EXCLUSIVE | INSERT, DELETE, UPDATE 수행 시 기본값 |
SHARE UPDATE | 드물게 사용되며 ROW SHARE와 유사 |
SHARE | 동시에 SELECT는 가능하지만 DML은 제한 |
SHARE ROW EXCLUSIVE | SHARE와 EXCLUSIVE의 중간 단계 |
EXCLUSIVE | 읽기, 쓰기 모두 제한 (완전 잠금) |
락 모드를 사용할 때는 트랜잭션 종료(COMMIT/ROLLBACK) 전까지 잠금이 유지됨