이번 문서의 목표: INSERT·UPDATE·DELETE·MERGE 네 가지 DML 문장의 정확한 문법을 쓸 수 있고, WHERE 절이 빠졌을 때 벌어지는 위험을 설명하며, MERGE가 조건에 따라 UPDATE와 INSERT를 자동으로 나눠 실행하는 원리를 이해한다.
1. DML이란 — 테이블 안의 데이터를 다루는 명령어
10편에서 DDL(CREATE·ALTER·DROP·TRUNCATE)이 테이블이라는 그릇 자체를 다룬다고 배웠습니다. 이번 편의 DML(Data Manipulation Language, 데이터 조작어)은 그 그릇 안에 담긴 데이터(행)를 넣고, 고치고, 지우는 명령어입니다. SELECT도 DML에 포함되지만, SELECT는 데이터를 조회만 할 뿐 변경하지 않으므로 이 편에서는 데이터를 실제로 변경하는 INSERT·UPDATE·DELETE·MERGE 네 문장만 다룹니다.
쉽게 말하면: DDL이 밥그릇을 굽는 일이라면, DML은 그 그릇에 밥을 담고(INSERT), 반찬을 바꾸고(UPDATE), 밥을 비우는(DELETE) 일상적인 손길입니다.
DML이 DDL과 결정적으로 다른 점은 자동 커밋되지 않는다는 것입니다. 10편에서 DDL은 실행 즉시 자동으로 커밋되어 롤백이 불가능하다고 배웠습니다. 반면 INSERT·UPDATE·DELETE·MERGE는 실행해도 곧바로 확정되지 않고, 직접 COMMIT을 입력하기 전까지는 ROLLBACK으로 취소할 수 있는 대기 상태로 남습니다. 트랜잭션과 COMMIT·ROLLBACK의 정확한 의미는 다음 12편에서 자세히 다루지만, 이번 편의 모든 예시에서 “아직 COMMIT하지 않았다면 되돌릴 수 있다”는 전제를 계속 사용합니다.
2. INSERT — 새 행 추가하기
INSERT는 테이블에 새로운 행을 한 건(또는 서브쿼리 결과만큼 여러 건) 추가하는 명령어입니다. 컬럼을 명시하는 방식과 생략하는 방식 두 가지가 있습니다.
-- 컬럼을 명시하는 방식(권장): 순서와 개수가 자유롭고 안전함
INSERT INTO 회원 (회원번호, 이름, 이메일) VALUES (10, '한지민', 'jimin@test.com');
-- 컬럼을 생략하는 방식: 테이블에 정의된 컬럼 순서를 그대로 따라야 함
INSERT INTO 회원 VALUES (11, '오세훈', 'sehun@test.com', 30, '일반');컬럼을 생략하면 테이블에 정의된 모든 컬럼에 순서대로 값을 채워야 하므로, 컬럼 순서가 바뀌거나 나중에 컬럼이 추가되면 오류가 나기 쉽습니다. 그래서 실무에서는 컬럼을 명시하는 방식을 훨씬 더 많이 씁니다.
실행 전(회원 테이블에 1건):
| 회원번호 | 이름 | 이메일 | 나이 | 등급 |
|---|---|---|---|---|
| 1 | 김민준 | minjun@test.com | 25 | 일반 |
INSERT INTO 회원 (회원번호, 이름, 이메일) VALUES (10, '한지민', 'jimin@test.com');실행 후(회원 테이블에 2건, 지정하지 않은 나이는 NULL, 등급은 10편에서 정의한 DEFAULT '일반'이 자동으로 채워짐):
| 회원번호 | 이름 | 이메일 | 나이 | 등급 |
|---|---|---|---|---|
| 1 | 김민준 | minjun@test.com | 25 | 일반 |
| 10 | 한지민 | jimin@test.com | NULL | 일반 |
또한 INSERT는 값을 직접 나열하는 대신, SELECT 서브쿼리의 결과를 그대로 여러 행 삽입할 수도 있습니다.
INSERT INTO 우수회원 (회원번호, 이름)
SELECT 회원번호, 이름 FROM 회원 WHERE 등급 = 'VIP';이 방식은 VALUES 없이 서브쿼리 하나로 여러 건을 한 번에 옮길 수 있어, 조건에 맞는 데이터를 다른 테이블로 복사할 때 자주 씁니다.
3. UPDATE — 기존 행 값 고치기
UPDATE는 이미 존재하는 행의 컬럼 값을 바꾸는 명령어입니다. SET 절에 “컬럼 = 새 값”을 나열하고, WHERE 절로 어떤 행을 바꿀지 지정합니다.
UPDATE 회원 SET 등급 = 'VIP' WHERE 회원번호 = 1;실행 전(회원 테이블):
| 회원번호 | 이름 | 등급 |
|---|---|---|
| 1 | 김민준 | 일반 |
| 10 | 한지민 | 일반 |
실행 후(회원번호 1의 등급만 변경됨, 다른 행은 그대로):
| 회원번호 | 이름 | 등급 |
|---|---|---|
| 1 | 김민준 | VIP |
| 10 | 한지민 | 일반 |
여러 컬럼을 한 번에 바꾸려면 쉼표로 나열합니다: UPDATE 회원 SET 등급 = 'VIP', 나이 = 26 WHERE 회원번호 = 1;. WHERE 절을 생략하면 어떻게 될까요? 테이블의 모든 행이 조건 없이 한꺼번에 바뀝니다. 예를 들어 UPDATE 회원 SET 등급 = 'VIP';를 실행하면 회원 테이블의 모든 회원이 다 VIP 등급으로 바뀝니다. UPDATE에서 WHERE를 빠뜨리는 실수는 DELETE만큼이나 위험하므로, 다음 절에서 DELETE와 함께 자세히 다룹니다.
4. DELETE — 행 삭제하기, WHERE 없는 DELETE의 위험
DELETE는 테이블에서 조건에 맞는 행을 삭제하는 DML 명령어입니다. 10편의 비교표에서 확인했듯, DELETE는 DML이므로 WHERE로 일부 행만 골라 지울 수 있고, 아직 COMMIT하지 않았다면 ROLLBACK으로 되돌릴 수 있습니다.
DELETE FROM 주문 WHERE 회원번호 = 100;실행 전(주문 테이블):
| 주문번호 | 회원번호 | 금액 |
|---|---|---|
| 1 | 100 | 5000 |
| 2 | 101 | 12000 |
| 3 | 100 | 3000 |
실행 후(회원번호 100인 행만 삭제됨):
| 주문번호 | 회원번호 | 금액 |
|---|---|---|
| 2 | 101 | 12000 |
여기서 WHERE 절을 빠뜨리면 어떻게 될까요?
DELETE FROM 주문;WHERE 절이 없으면 데이터베이스는 “조건에 맞는 행을 골라 지워라”가 아니라 “조건이 없으니 모든 행이 대상이다”라고 해석합니다. 그 결과 주문 테이블의 모든 행이 한꺼번에 삭제됩니다.
실행 후(WHERE 없는 DELETE 실행 결과, 테이블은 남아 있지만 행이 0건):
| 주문번호 | 회원번호 | 금액 |
|---|---|---|
| (전체 삭제됨, 행 없음) |
자주 틀리는 점 5 — WHERE 없는 DELETE와 TRUNCATE를 같은 것으로 착각. WHERE 없는 DELETE FROM 주문;과 TRUNCATE TABLE 주문;은 “모든 행이 사라진다”는 결과는 똑같아 보이지만 전혀 다른 명령입니다. DELETE는 여전히 DML이라 실행 직후 아직 COMMIT하지 않았다면 ROLLBACK으로 삭제를 취소하고 3건을 되살릴 수 있습니다. 반면 TRUNCATE는 DDL이라 실행되는 순간 자동 커밋되어 ROLLBACK으로 되돌릴 수 없습니다. 실무에서 WHERE를 빠뜨린 DELETE 한 줄이 대형 사고로 이어지는 이유는, 조건절을 빠뜨렸다는 사실을 실행한 뒤에야 깨닫는 경우가 많기 때문입니다. 프로덕션 환경에서 DELETE·UPDATE를 실행하기 전에는 먼저 같은 조건으로 SELECT를 실행해 “지워질 대상이 정말 내가 원하는 행인지” 눈으로 확인하는 습관이 안전합니다.
5. MERGE — 있으면 UPDATE, 없으면 INSERT (UPSERT)
실무에서는 “이 회원이 이미 존재하면 정보를 갱신하고, 존재하지 않으면 새로 추가하라”는 요구가 자주 발생합니다. 이를 IF문 없이 SQL 한 문장으로 처리하는 것이 MERGE입니다. UPDATE와 INSERT를 합쳤다는 뜻에서 이런 동작을 흔히 UPSERT(UPDATE + INSERT)라고 부릅니다.
MERGE의 동작 원리는 다음과 같습니다.
- USING 절에 지정한 원본 데이터(다른 테이블이나 서브쿼리)의 각 행을 하나씩 가져온다.
- ON 절에 지정한 조건으로, 그 행에 대응하는 행이 대상 테이블에 이미 있는지 검사한다.
- 이미 있으면(WHEN MATCHED) UPDATE를, 없으면(WHEN NOT MATCHED) INSERT를 실행한다.
MERGE INTO 재고 T
USING 입고내역 S
ON (T.상품코드 = S.상품코드)
WHEN MATCHED THEN
UPDATE SET T.수량 = T.수량 + S.입고수량
WHEN NOT MATCHED THEN
INSERT (상품코드, 수량) VALUES (S.상품코드, S.입고수량);실행 전(재고 테이블에 2건, 입고내역 테이블에 2건):
| 상품코드 | 수량 |
|---|---|
| A001 | 10 |
| A002 | 5 |
| 상품코드 | 입고수량 |
|---|---|
| A001 | 3 |
| A003 | 7 |
A001은 재고 테이블에 이미 존재하므로 WHEN MATCHED가 실행되어 수량이 더해지고, A003은 재고 테이블에 없으므로 WHEN NOT MATCHED가 실행되어 새 행으로 삽입됩니다. A002는 입고내역에 없으므로 아무 처리도 받지 않고 그대로 남습니다.
실행 후(재고 테이블):
| 상품코드 | 수량 |
|---|---|
| A001 | 13 |
| A002 | 5 |
| A003 | 7 |
자주 틀리는 점 6 — MERGE를 쓰지 않고 IF문으로 처리해야 한다고 착각. MERGE 없이 같은 결과를 만들려면 “UPDATE를 실행해 보고, 영향받은 행이 0건이면 INSERT를 실행한다”는 절차형 로직(프로시저 등)을 직접 짜야 합니다. MERGE는 이 판단을 SQL 문장 하나로 대신 처리해 준다는 것이 핵심 가치입니다. 또한 WHEN MATCHED나 WHEN NOT MATCHED 중 하나만 써도 문법상 가능하다는 점, ON 절의 조건은 보통 기본키나 유일한 값(위 예시의 상품코드)으로 잡아야 “행 하나에 정확히 대응”된다는 점도 함께 기억해야 합니다.
6. DML과 트랜잭션의 관계
이번 편에서 실행한 모든 INSERT·UPDATE·DELETE·MERGE 예시는 전부 “아직 COMMIT하지 않은 상태”를 전제로 설명했습니다. 이는 우연이 아니라 DML의 근본적인 성질입니다. DML은 실행한다고 즉시 데이터베이스에 영구 반영되는 것이 아니라, COMMIT을 만나야 비로소 확정됩니다. 그전까지는 같은 세션(session, 현재 접속해 작업 중인 연결)에서 임시로 반영된 것처럼 보일 뿐이며, 언제든 ROLLBACK으로 취소할 수 있습니다.
반대로 10편에서 다룬 DDL은 실행되는 순간 자동으로 커밋됩니다. 그래서 “DELETE는 되돌릴 수 있지만 TRUNCATE는 되돌릴 수 없다”는 차이가 생기는 것입니다. COMMIT과 ROLLBACK이 정확히 무엇을 확정하고 취소하는지, 그리고 SAVEPOINT로 일부만 되돌리는 방법은 다음 12편에서 이어서 다룹니다.
직접 해보기
00편에서 만든 실습 환경(Docker + Oracle + DBeaver)에서 진행합니다. 아직 만들지 않았다면 00편을 먼저 보세요.
seed의 원본 사원 테이블은 절대 건드리지 않는다. 원본이 바뀌면 다른 편의 예제가 이 문서와 다른 결과를 낸다. 대신 아래처럼 복제본을 만들어 그 위에서만 INSERT·UPDATE·DELETE를 연습한다.
CREATE TABLE 연습 AS SELECT * FROM 사원;
INSERT INTO 연습 (사원번호, 사원명, 커미션) VALUES (200, '신입사원', NULL);
SELECT * FROM 연습 WHERE 사원번호 = 200;
UPDATE 연습 SET 커미션 = 999 WHERE 사원번호 = 100;
SELECT * FROM 연습 WHERE 사원번호 = 100;
DELETE FROM 연습 WHERE 사원번호 = 103;
SELECT * FROM 연습;무엇을 보아야 하나: 각 문장 실행 직후의 SELECT 결과가 방금 실행한 INSERT·UPDATE·DELETE와 정확히 일치하는지 확인한다. 마지막 SELECT * FROM 연습;에는 몇 행이 남아야 하는지 미리 계산해 보고 맞춰 본다.
왜 이걸 해보나: DML은 결과를 눈으로 확인하지 않으면 “됐겠지” 하고 넘어가기 쉽다. 매번 SELECT로 확인하는 습관이 실무에서 실수를 줄인다.
실습이 끝나면 복제본을 정리한다.
DROP TABLE 연습;핵심 정리
- INSERT는 새 행을 추가한다. 컬럼을 명시하는 방식이 순서·개수 오류를 막아 더 안전하며, 서브쿼리로 여러 행을 한 번에 옮길 수도 있다
- UPDATE는 SET으로 값을, WHERE로 대상을 지정한다. WHERE를 빠뜨리면 테이블의 모든 행이 한꺼번에 바뀐다
- DELETE는 WHERE로 일부 행만 지울 수 있는 DML이다. WHERE를 빠뜨리면 전체 행이 삭제되지만, TRUNCATE와 달리 COMMIT 전이면 ROLLBACK으로 되살릴 수 있다
- MERGE는 USING·ON으로 대응 행을 찾아 있으면 UPDATE(WHEN MATCHED), 없으면 INSERT(WHEN NOT MATCHED)를 자동으로 나눠 실행하는 UPSERT 문장이다
- DML은 DDL과 달리 자동 커밋되지 않으며, 직접 COMMIT하기 전까지는 ROLLBACK으로 되돌릴 수 있는 대기 상태로 남는다
마무리 복습
DELETE FROM 주문;
TRUNCATE TABLE 주문;