SQLSQL 기초 · 6입문

INSERT, UPDATE, DELETE — 데이터 변경하기

SQLINSERTUPDATEDELETE트랜잭션UPSERT

INSERT: 데이터 삽입

-- 단일 행 삽입
INSERT INTO employees (name, department, salary, hire_date)
VALUES ('신입사원', '개발팀', 3500000, '2026-04-21');

-- 여러 행 한 번에
INSERT INTO employees (name, department, salary, hire_date)
VALUES
    ('김A', '개발팀', 4000000, '2026-04-21'),
    ('이B', '마케팅팀', 3800000, '2026-04-21'),
    ('박C', '디자인팀', 4200000, '2026-04-21');

-- 삽입 후 생성된 ID 반환 (PostgreSQL)
INSERT INTO employees (name, department, salary)
VALUES ('정D', '개발팀', 4500000)
RETURNING id, name;

UPDATE: 데이터 수정

-- 특정 행 수정 (WHERE 필수!)
UPDATE employees
SET salary = 5500000
WHERE id = 1;

-- 여러 열 동시 수정
UPDATE employees
SET
    salary = salary * 1.1,        -- 10% 인상
    department = '시니어개발팀'
WHERE department = '개발팀' AND salary < 5000000;

-- 결과 확인
UPDATE employees
SET salary = 6000000
WHERE id = 2
RETURNING id, name, salary;

-- ⚠️ WHERE 없으면 모든 행 수정!
-- UPDATE employees SET salary = 0;  -- 전 직원 급여 0으로!

DELETE: 데이터 삭제

-- 특정 행 삭제
DELETE FROM employees WHERE id = 10;

-- 조건에 맞는 여러 행
DELETE FROM employees
WHERE hire_date < '2020-01-01' AND is_active = FALSE;

-- 삭제된 행 반환
DELETE FROM employees WHERE id = 5
RETURNING *;

-- 테이블 전체 비우기 (빠른 방법)
TRUNCATE TABLE employees;
TRUNCATE TABLE employees RESTART IDENTITY;  -- ID 시퀀스도 초기화

트랜잭션

여러 작업을 하나의 단위로 묶어 모두 성공하거나 모두 실패하게 합니다.

-- 계좌 이체 예시
BEGIN;

UPDATE accounts SET balance = balance - 10000 WHERE id = 1;  -- A 출금
UPDATE accounts SET balance = balance + 10000 WHERE id = 2;  -- B 입금

-- 잔액 확인
SELECT id, balance FROM accounts WHERE id IN (1, 2);

-- 문제 없으면
COMMIT;

-- 문제 있으면
ROLLBACK;

SAVEPOINT

트랜잭션 내 중간 저장점을 설정합니다.

BEGIN;

INSERT INTO orders (customer_id, amount) VALUES (1, 50000);
SAVEPOINT after_order;  -- 저장점

INSERT INTO order_items (order_id, product_id) VALUES (LASTVAL(), 99);
-- 실패 시 order는 살리고 item만 취소
ROLLBACK TO SAVEPOINT after_order;

COMMIT;

UPSERT: 있으면 UPDATE, 없으면 INSERT

-- ON CONFLICT DO UPDATE (PostgreSQL)
INSERT INTO user_settings (user_id, theme, language)
VALUES (1, 'dark', 'ko')
ON CONFLICT (user_id)
DO UPDATE SET
    theme = EXCLUDED.theme,
    language = EXCLUDED.language,
    updated_at = NOW();

-- ON CONFLICT DO NOTHING (무시)
INSERT INTO email_subscribers (email)
VALUES ('kim@example.com')
ON CONFLICT (email) DO NOTHING;

데이터 변경 안전 체크리스트

-- ✅ UPDATE/DELETE 전 SELECT로 대상 확인
SELECT * FROM employees WHERE department = '구개발팀';

-- 확인 후 UPDATE
UPDATE employees SET department = '개발팀' WHERE department = '구개발팀';

-- ✅ 트랜잭션 사용
BEGIN;
DELETE FROM old_logs WHERE created_at < NOW() - INTERVAL '1 year';
-- 삭제된 수 확인
SELECT ROW_COUNT();  -- MySQL
-- RETURNING 으로 확인
COMMIT;

정리

명령어역할
INSERT INTO ... VALUES행 삽입
INSERT ... RETURNING삽입 후 값 반환
UPDATE ... SET ... WHERE행 수정
DELETE FROM ... WHERE행 삭제
TRUNCATE테이블 전체 삭제
BEGIN/COMMIT/ROLLBACK트랜잭션
ON CONFLICT DO UPDATEUPSERT

다음 편에서는 DDL과 인덱스 — 테이블 구조를 설계하고 쿼리 성능을 높이는 방법을 배웁니다.

궁금한 점이 있으신가요?

협업·의뢰는 아래로, 가벼운 소통은 인스타그램 @bluefox._.hi도 환영이에요.