백엔드 데이터 인프라 8편 — SQL 기초 5가지 동사

2026-05-17백엔드 데이터 인프라

백엔드 데이터 인프라 8편. SQL의 다섯 가지 핵심 동사 SELECT·INSERT·UPDATE·DELETE·MERGE를 PG 18 기준으로 풀어쓴 학습 노트.

📚 백엔드 데이터 인프라 · 8편 — SQL 기초 5가지 동사

이 글은 백엔드 데이터 인프라 시리즈 70편 중 8편이에요. 7편 관계형 모델 까지 "개념" 을 다뤘으니, 이번 8편은 그 개념을 코드로 표현하는 언어 — SQL.

SQL이 헷갈리는 이유

SQL = "Structured Query Language". 단어 "Query" 가 박혀 있어서 처음 보면 "조회 언어인가?" 헷갈려요. 사실 SQL은 조회 + 생성·수정·삭제 까지 다 하는 만능 언어. "동사 5개" 만 외우면 90% 시나리오 끝.

이 글에서는 다섯 가지 동사 를 한 번에 짚어요. SELECT는 조회, INSERT는 생성, UPDATE는 수정, DELETE는 삭제, 그리고 MERGE는 있으면 수정·없으면 생성하는 UPSERT(있으면 갱신, 없으면 추가). 다섯 동사가 SQL의 뼈대예요.

SELECT — 데이터 조회

가장 자주 쓰는 동사. 표준 형태:

SELECT  컬럼1, 컬럼2, ...
FROM    테이블
WHERE   조건
ORDER BY 컬럼
LIMIT   개수
OFFSET  시작 위치;

기본 예

-- 모든 컬럼
SELECT * FROM users;

-- 특정 컬럼
SELECT id, name, email FROM users;

-- 조건 필터
SELECT name, email FROM users WHERE id = 1;

-- 정렬
SELECT * FROM users ORDER BY created_at DESC;

-- 페이지네이션
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;

별칭 (AS)

SELECT
    name        AS user_name,
    email       AS user_email,
    COUNT(*)    AS total
FROM users
GROUP BY name, email;

AS 키워드로 결과 컬럼명 변경. 생략 가능 (name user_name) 이지만 명시 권장.

DISTINCT

SELECT DISTINCT country FROM users;   -- 중복 제거

집계 함수

SELECT COUNT(*) FROM users;
SELECT AVG(amount) FROM orders;
SELECT MIN(created_at), MAX(created_at) FROM orders;
SELECT SUM(amount) FROM orders WHERE status = 'COMPLETED';

COUNT·AVG·MIN·MAX·SUM 5대 집계 함수. 11~14편에서 깊이.

INSERT — 데이터 생성

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

단건

INSERT INTO users (name, email)
VALUES ('Alice', 'alice@example.com');

기본 키(id)는 BIGSERIAL(자동 증가 정수 타입)이라 자동.

여러 건 (Bulk)

INSERT INTO users (name, email) VALUES
    ('Alice', 'alice@example.com'),
    ('Bob',   'bob@example.com'),
    ('Charlie', 'charlie@example.com');

한 SQL로 여러 행 — 단건씩 N번보다 N배 이상 빠름. 대량 입력 표준.

RETURNING — PG 특별 기능

INSERT INTO users (name, email)
VALUES ('Alice', 'alice@example.com')
RETURNING id, created_at;

INSERT 직후 — 생성된 행을 결과로 반환. "자동 증가 ID 알아내기" 표준 패턴. JPA(자바 객체-DB 매핑 표준)의 @GeneratedValue 도 내부적으로 이걸 활용.

SELECT로 INSERT

INSERT INTO archive_users (id, name, email)
SELECT id, name, email FROM users WHERE created_at < '2025-01-01';

다른 쿼리 결과를 그대로 입력. 데이터 이관·아카이브 표준.

ON CONFLICT — UPSERT

INSERT INTO users (id, name, email)
VALUES (1, 'Alice', 'alice@example.com')
ON CONFLICT (id)
DO UPDATE SET name = EXCLUDED.name, email = EXCLUDED.email;

기본 키 충돌 시 UPDATE — "있으면 수정·없으면 생성". PG 9.5+ 표준. MERGE 와 함께 자주.

-- 충돌 시 그냥 무시
INSERT INTO users (id, name) VALUES (1, 'Alice')
ON CONFLICT (id) DO NOTHING;

UPDATE — 데이터 수정

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

단건

UPDATE users
SET    name = 'Alice Smith'
WHERE  id = 1;

여러 컬럼 동시

UPDATE users
SET    name = 'Alice Smith',
       email = 'alice.smith@example.com'
WHERE  id = 1;

다른 테이블 값으로 (FROM)

UPDATE users
SET    last_login = activities.last_at
FROM   activities
WHERE  users.id = activities.user_id;

UPDATE FROM 구문 — PG의 강점. 다른 테이블 값을 한 번에 반영.

RETURNING

UPDATE users SET name = 'Alice Smith' WHERE id = 1
RETURNING id, name, updated_at;

수정된 행을 결과로. INSERT 와 동일.

함정 — WHERE 누락

UPDATE users SET name = 'Test';   -- ❌ 모든 행 수정!

운영 환경에서 가장 무서운 실수. 항상 WHERE + 가능하면 트랜잭션 BEGIN 후 SELECT 검증 → UPDATE → COMMIT.

DELETE — 데이터 삭제

DELETE FROM 테이블 WHERE 조건;

기본

DELETE FROM users WHERE id = 1;

RETURNING

DELETE FROM users WHERE id = 1
RETURNING id, name, email;

USING (다른 테이블 참조)

DELETE FROM users
USING bans
WHERE users.id = bans.user_id;

TRUNCATE — 전체 삭제 빠르게

TRUNCATE TABLE users;

DELETE 와 차이를 보면, TRUNCATE는 행 단위 처리를 건너뛰어서 매우 빠르고 AUTO_INCREMENT까지 초기화돼요. 반면 DELETE WHERE 1=1 은 행마다 트리거·로그가 돌아서 느려요.

대량 삭제 = TRUNCATE 권장. 단 — 외래 키로 참조되는 테이블은 못 비움.

함정 — WHERE 누락

DELETE FROM users;   -- ❌ 모든 행 삭제!

UPDATE 와 같은 무서운 실수. 운영 = BEGIN; DELETE ...; SELECT COUNT(*); COMMIT; 흐름.

MERGE — UPSERT 표준 (PG 15+)

PG 15 부터 SQL 표준 MERGE 지원.

MERGE INTO users AS target
USING (VALUES (1, 'Alice', 'alice@example.com')) AS source(id, name, email)
ON target.id = source.id
WHEN MATCHED THEN
    UPDATE SET name = source.name, email = source.email
WHEN NOT MATCHED THEN
    INSERT (id, name, email) VALUES (source.id, source.name, source.email);

복잡한 "있으면 수정·없으면 생성·조건에 따라 삭제" 시나리오에 강함. 단순한 경우 = INSERT ... ON CONFLICT 가 더 깔끔.

동사 5개 한눈에

동사 의미 표준 패턴
SELECT 조회 SELECT 컬럼 FROM 테이블 WHERE 조건
INSERT 생성 INSERT INTO 테이블 (컬럼) VALUES (값) RETURNING *
UPDATE 수정 UPDATE 테이블 SET 컬럼=값 WHERE 조건 RETURNING *
DELETE 삭제 DELETE FROM 테이블 WHERE 조건 RETURNING *
MERGE UPSERT MERGE INTO ... USING ... WHEN MATCHED THEN ... WHEN NOT MATCHED THEN ...

트랜잭션과의 조합

자바 백엔드 입문 43편 @Transactional 패턴 PG 직접:

BEGIN;
    INSERT INTO orders (user_id, amount) VALUES (1, 10000) RETURNING id;
    -- 12345 라는 ID 반환됐다 가정
    UPDATE users SET point = point - 10000 WHERE id = 1;
COMMIT;

-- 실패 시
ROLLBACK;

5개 동사 + BEGIN·COMMIT·ROLLBACK 3개 = SQL의 핵심 8개 키워드.

Spring 백엔드 흐름

JPA가 자바 객체 ↔ 이 5개 동사 자동 매핑.

JPA 메서드 자동 생성 SQL
repository.save(user) (신규) INSERT + RETURNING id
repository.save(user) (기존) UPDATE
repository.findById(id) SELECT
repository.delete(user) DELETE

JPA가 "자동 짜주지만" — 자동 생성된 SQL이 어떤 형태인지 알아야 트러블슈팅 가능. 40편 EXPLAIN 에서 깊이.

함정 5가지

(1) WHERE 누락의 재앙

UPDATE·DELETE 시 WHERE 없으면 — 모든 행. 운영 = BEGINSELECT 검증 → UPDATE/DELETE → 확인 → COMMIT.

(2) NULL 처리

WHERE col = NULL   ❌
WHERE col IS NULL  ✅

7편 NULL 참고.

(3) 문자열 따옴표 — 작은 따옴표 (single quote)

SELECT * FROM users WHERE name = 'Alice';   ✅
SELECT * FROM users WHERE name = "Alice";   ❌ — 큰 따옴표는 식별자(컬럼명)

PG에서 작은 따옴표 '문자열' 은 문자열 리터럴, 큰 따옴표 "이름" 은 식별자(테이블·컬럼 이름)예요. 둘은 완전히 다른 역할.

(4) RETURNING 잊음

JPA가 안 알려줘서 잘 안 쓰지만 — 직접 SQL 쓸 때 RETURNING 매우 유용.

(5) UPSERT 시 EXCLUDED 안 박음

INSERT INTO users (id, name) VALUES (1, 'Alice')
ON CONFLICT (id)
DO UPDATE SET name = 'Alice';   -- ❌ 항상 'Alice' (의도 X)

ON CONFLICT (id)
DO UPDATE SET name = EXCLUDED.name;   -- ✅ INSERT 시 값

EXCLUDED = "INSERT 하려던 값" 의미. 모르면 UPSERT 헷갈림.

⚠️ 운영 안전 룰

UPDATE·DELETE 운영 실행은 BEGIN → SELECT 검증 → 실행 → COUNT 확인 → COMMIT 흐름. 의도와 다른 결과면 ROLLBACK. 매번 백업·확인. 다른 사람에게 한 번 더 검토.

한 줄 정리 — SQL 5대 동사 = SELECT·INSERT·UPDATE·DELETE·MERGE. PG 특별 = RETURNING·ON CONFLICT·FROM/USING. WHERE 누락이 운영 가장 무서운 함정. JPA의 자동 SQL을 직접 짤 줄 알아야 운영 단계 가능.

시험 직전 한 번 더 — SQL 기초 입문자가 매번 헷갈리는 것

  • SQL 5대 동사 = SELECT·INSERT·UPDATE·DELETE·MERGE
  • 표준 SELECT = SELECT 컬럼 FROM 테이블 WHERE 조건 ORDER BY ... LIMIT ...
  • 별칭 = AS alias
  • 집계 = COUNT·AVG·MIN·MAX·SUM
  • DISTINCT = 중복 제거
  • INSERT 여러 건 = 한 SQL에 콤마로 여러 VALUES
  • RETURNING = 생성·수정된 행 반환 (PG 특별)
  • ON CONFLICT = UPSERT (PG 9.5+)
  • EXCLUDED = 충돌 시 INSERT 하려던 값
  • INSERT SELECT = 다른 쿼리 결과 입력
  • UPDATE SET col=val WHERE 조건
  • UPDATE FROM = 다른 테이블 값으로 (PG 강점)
  • DELETE FROM 테이블 WHERE 조건
  • DELETE USING = 다른 테이블 참조해 삭제
  • TRUNCATE = 전체 삭제 빠름 (FK 없는 테이블)
  • MERGE = SQL 표준 UPSERT (PG 15+)
  • 작은 따옴표 = 문자열, 큰 따옴표 = 식별자
  • NULL = IS NULL (= NULL 거짓)
  • WHERE 누락 = 모든 행 적용 — 가장 무서운 함정
  • 운영 = BEGIN → SELECT 검증 → 실행 → ROLLBACK or COMMIT
  • BEGIN·COMMIT·ROLLBACK = 트랜잭션 3대 키워드
  • JPA save = INSERT 또는 UPDATE 자동
  • 직접 SQL 모르면 운영 트러블슈팅 불가

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!