본문 바로가기
카테고리 없음

SQL INSERT, UPDATE, DELETE 쿼리 완벽 가이드

by quantone 2026. 1. 17.

 

1. INSERT - 데이터 삽입

기본 문법

INSERT INTO 테이블명 (컬럼1, 컬럼2, 컬럼3, ...)
VALUES (값1, 값2, 값3, ...);

예제 1: 모든 컬럼에 데이터 삽입

-- users 테이블에 새로운 사용자 추가
INSERT INTO users (id, name, email, age, created_at)
VALUES (1, '김철수', 'kim@example.com', 25, '2024-01-15');

예제 2: 일부 컬럼만 지정

-- 특정 컬럼만 지정 (나머지는 기본값 또는 NULL)
INSERT INTO users (name, email)
VALUES ('이영희', 'lee@example.com');

예제 3: 여러 행 한 번에 삽입

INSERT INTO users (name, email, age)
VALUES 
    ('박민수', 'park@example.com', 30),
    ('정수진', 'jung@example.com', 28),
    ('최동욱', 'choi@example.com', 35);

예제 4: SELECT 결과를 삽입

-- 다른 테이블의 데이터를 조회하여 삽입
INSERT INTO users_backup (name, email, age)
SELECT name, email, age 
FROM users 
WHERE age > 30;

예제 5: 기본값 사용

-- DEFAULT 키워드로 기본값 사용
INSERT INTO products (product_name, price, stock)
VALUES ('노트북', 1500000, DEFAULT);

2. UPDATE - 데이터 수정

기본 문법

UPDATE 테이블명
SET 컬럼1 = 값1, 컬럼2 = 값2, ...
WHERE 조건;

⚠️ 주의: WHERE 절을 빠뜨리면 모든 행이 수정됩니다!

예제 1: 단일 컬럼 수정

-- 특정 사용자의 이메일 변경
UPDATE users
SET email = 'newemail@example.com'
WHERE id = 1;

예제 2: 여러 컬럼 동시 수정

-- 여러 정보를 한 번에 수정
UPDATE users
SET email = 'update@example.com',
    age = 26,
    updated_at = NOW()
WHERE name = '김철수';

예제 3: 조건에 맞는 여러 행 수정

-- 30세 이상 모든 사용자의 등급 상향
UPDATE users
SET membership_level = 'GOLD'
WHERE age >= 30;

예제 4: 계산식으로 수정

-- 모든 제품 가격 10% 인상
UPDATE products
SET price = price * 1.1;

-- 재고 5개 감소
UPDATE products
SET stock = stock - 5
WHERE product_id = 101;

예제 5: 서브쿼리를 이용한 수정

-- 평균 나이보다 많은 사용자의 상태 변경
UPDATE users
SET status = 'SENIOR'
WHERE age > (SELECT AVG(age) FROM users);

예제 6: CASE 문을 이용한 조건부 수정

-- 나이대별로 다른 등급 부여
UPDATE users
SET grade = CASE
    WHEN age < 20 THEN 'TEEN'
    WHEN age BETWEEN 20 AND 30 THEN 'YOUNG'
    WHEN age BETWEEN 31 AND 50 THEN 'ADULT'
    ELSE 'SENIOR'
END;

3. DELETE - 데이터 삭제

기본 문법

DELETE FROM 테이블명
WHERE 조건;

⚠️ 주의: WHERE 절을 빠뜨리면 모든 데이터가 삭제됩니다!

예제 1: 특정 행 삭제

-- ID가 1인 사용자 삭제
DELETE FROM users
WHERE id = 1;

예제 2: 조건에 맞는 여러 행 삭제

-- 30세 미만 사용자 모두 삭제
DELETE FROM users
WHERE age < 30;

-- 비활성 계정 삭제
DELETE FROM users
WHERE status = 'INACTIVE' AND last_login < '2023-01-01';

예제 3: 서브쿼리를 이용한 삭제

-- 주문 내역이 없는 사용자 삭제
DELETE FROM users
WHERE id NOT IN (SELECT DISTINCT user_id FROM orders);

예제 4: JOIN을 이용한 삭제 (MySQL)

-- 주문이 없는 제품 삭제
DELETE p
FROM products p
LEFT JOIN orders o ON p.product_id = o.product_id
WHERE o.product_id IS NULL;

예제 5: 모든 데이터 삭제

-- 모든 행 삭제 (구조는 유지)
DELETE FROM users;

-- 또는 TRUNCATE 사용 (더 빠름, AUTO_INCREMENT 초기화)
TRUNCATE TABLE users;

4. 실전 활용 예제

시나리오 1: 회원가입 처리

-- 신규 회원 등록
INSERT INTO users (name, email, password, created_at)
VALUES ('홍길동', 'hong@example.com', 'hashed_password', NOW());

-- 가입 축하 포인트 지급
UPDATE users
SET points = 1000
WHERE email = 'hong@example.com';

시나리오 2: 주문 처리

-- 주문 생성
INSERT INTO orders (user_id, product_id, quantity, order_date)
VALUES (5, 101, 2, NOW());

-- 재고 차감
UPDATE products
SET stock = stock - 2
WHERE product_id = 101;

시나리오 3: 데이터 정리

-- 1년 이상 로그인하지 않은 사용자 삭제
DELETE FROM users
WHERE last_login < DATE_SUB(NOW(), INTERVAL 1 YEAR);

-- 관련 데이터도 함께 삭제 (외래키 ON DELETE CASCADE가 없는 경우)
DELETE FROM user_logs WHERE user_id IN (
    SELECT id FROM users WHERE last_login < DATE_SUB(NOW(), INTERVAL 1 YEAR)
);

시나리오 4: 대량 데이터 처리

-- 대량 삽입 (성능 최적화)
INSERT INTO logs (user_id, action, created_at)
VALUES 
    (1, 'login', NOW()),
    (2, 'purchase', NOW()),
    (3, 'logout', NOW()),
    (1, 'view', NOW()),
    (2, 'search', NOW());

-- 조건부 대량 업데이트
UPDATE products
SET discount_rate = CASE
    WHEN category = 'ELECTRONICS' THEN 0.15
    WHEN category = 'CLOTHING' THEN 0.20
    WHEN category = 'BOOKS' THEN 0.10
    ELSE 0.05
END
WHERE sale_event = TRUE;

5. 중요 개념 및 주의사항

트랜잭션 사용

-- 여러 작업을 하나의 단위로 처리
START TRANSACTION;

UPDATE accounts SET balance = balance - 10000 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 10000 WHERE user_id = 2;

COMMIT;  -- 성공 시 저장
-- ROLLBACK;  -- 실패 시 취소

WHERE 절 없이 실행 방지

-- 안전 모드 활성화 (MySQL Workbench)
SET SQL_SAFE_UPDATES = 1;

-- 이제 WHERE 없는 UPDATE/DELETE는 오류 발생
UPDATE users SET age = 30;  -- 오류!

조건 확인 후 실행

-- 먼저 SELECT로 확인
SELECT * FROM users WHERE age < 20;

-- 확인 후 삭제
DELETE FROM users WHERE age < 20;

AUTO_INCREMENT 처리

-- INSERT 시 자동 증가 컬럼은 생략
INSERT INTO users (name, email)  -- id는 자동 생성
VALUES ('테스트', 'test@example.com');

-- 마지막 삽입된 ID 확인
SELECT LAST_INSERT_ID();

6. 데이터베이스별 차이점

MySQL

-- 중복 시 무시
INSERT IGNORE INTO users (id, name) VALUES (1, '홍길동');

-- 중복 시 업데이트
INSERT INTO users (id, name, email) 
VALUES (1, '홍길동', 'hong@example.com')
ON DUPLICATE KEY UPDATE email = 'hong@example.com';

-- LIMIT 사용 가능
DELETE FROM users WHERE age < 20 LIMIT 10;

PostgreSQL

-- RETURNING으로 삽입된 데이터 반환
INSERT INTO users (name, email)
VALUES ('홍길동', 'hong@example.com')
RETURNING id, created_at;

-- UPSERT (충돌 시 업데이트)
INSERT INTO users (id, name, email)
VALUES (1, '홍길동', 'hong@example.com')
ON CONFLICT (id) 
DO UPDATE SET email = EXCLUDED.email;

SQL Server

-- OUTPUT으로 변경된 데이터 확인
DELETE FROM users
OUTPUT DELETED.*
WHERE age < 20;

-- MERGE 문 (INSERT + UPDATE + DELETE)
MERGE INTO target_table AS target
USING source_table AS source
ON target.id = source.id
WHEN MATCHED THEN UPDATE SET target.name = source.name
WHEN NOT MATCHED THEN INSERT (id, name) VALUES (source.id, source.name);

7. 성능 최적화 팁

1. 인덱스 활용

-- WHERE 절에 사용되는 컬럼에 인덱스 생성
CREATE INDEX idx_age ON users(age);

-- 이제 이 쿼리가 빨라집니다
DELETE FROM users WHERE age < 20;

2. 배치 처리

-- 나쁜 예: 반복문으로 하나씩 삽입
-- INSERT INTO users (name) VALUES ('A');
-- INSERT INTO users (name) VALUES ('B');

-- 좋은 예: 한 번에 여러 행 삽입
INSERT INTO users (name) VALUES ('A'), ('B'), ('C'), ('D');

3. 조건 최적화

-- 나쁜 예: 함수 사용
DELETE FROM users WHERE YEAR(created_at) = 2020;

-- 좋은 예: 인덱스 활용 가능
DELETE FROM users 
WHERE created_at >= '2020-01-01' AND created_at < '2021-01-01';

8. 자주 발생하는 오류와 해결

오류 1: 외래키 제약 조건

-- 오류: 참조되는 데이터는 삭제 불가
DELETE FROM users WHERE id = 1;
-- ERROR: Cannot delete - foreign key constraint fails

-- 해결: 참조하는 데이터 먼저 삭제
DELETE FROM orders WHERE user_id = 1;
DELETE FROM users WHERE id = 1;

오류 2: 중복 키

-- 오류: 기본키 중복
INSERT INTO users (id, name) VALUES (1, '홍길동');
-- ERROR: Duplicate entry '1' for key 'PRIMARY'

-- 해결: 다른 ID 사용 또는 UPDATE 사용
UPDATE users SET name = '홍길동' WHERE id = 1;

오류 3: NULL 제약

-- 오류: NOT NULL 컬럼에 NULL 삽입
INSERT INTO users (name) VALUES (NULL);
-- ERROR: Column 'name' cannot be null

-- 해결: 값 제공
INSERT INTO users (name) VALUES ('이름없음');

9. 보안 Best Practices

SQL Injection 방지

-- 위험: 사용자 입력을 직접 쿼리에 포함
-- DELETE FROM users WHERE name = '" + userInput + "';

-- 안전: Prepared Statement 사용 (코드 예시)

Java 예시:

String sql = "DELETE FROM users WHERE name = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, userInput);
pstmt.executeUpdate();

Python 예시:

cursor.execute("DELETE FROM users WHERE name = %s", (user_input,))

10. 실습 문제

아래 users 테이블로 연습해보세요:

-- 테이블 생성
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE,
    age INT,
    status VARCHAR(20) DEFAULT 'ACTIVE',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

문제 1: 새로운 사용자 3명을 한 번에 추가하세요.

문제 2: 나이가 25세인 모든 사용자의 상태를 'VERIFIED'로 변경하세요.

문제 3: 이메일이 없는 사용자를 모두 삭제하세요.

문제 4: 모든 사용자의 나이를 1씩 증가시키세요.

문제 5: 'INACTIVE' 상태이면서 1년 이상 된 사용자를 삭제하세요.


마무리

INSERT, UPDATE, DELETE는 데이터베이스의 핵심 작업입니다.

기억해야 할 핵심:

  • ✅ 항상 WHERE 절을 신중하게 작성하세요
  • ✅ 중요한 작업 전에는 SELECT로 먼저 확인하세요
  • ✅ 트랜잭션을 활용하여 데이터 무결성을 보장하세요
  • ✅ 백업을 정기적으로 수행하세요
  • ✅ Prepared Statement로 SQL Injection을 방지하세요