DP-900 공식 출제 범위 도메인 2에는 "일반적인 SQL 문 식별"과 "관계형 데이터의 특징 식별"이 들어 있습니다. 실제 문제는 SQL을 직접 작성하게 하지 않고, "이 명령은 DDL인가 DML인가", "주문 테이블에 없는 고객 ID가 들어가지 못하게 막는 것은 무엇인가"처럼 분류와 규칙을 묻습니다. 개념만 정확히 잡으면 개발 경험이 없어도 충분히 맞힐 수 있는 영역입니다.
이 글은 DP-900 학습자료 중 관계형 데이터 기본 개념 편의 보충편입니다. 그 글에서 다룬 SELECT·INSERT·UPDATE·DELETE·JOIN과 키, 정규화를 이어받아 SQL 문의 분류, 조회 문을 읽는 순서, 제약 조건과 세 가지 무결성, NULL, 인덱스 유형, 비정규화까지 시험에 자주 나오는 순서대로 정리합니다.
---
SQL은 왜 여러 갈래로 나뉠까?
새 건물을 짓는 과정을 떠올려 보세요. 먼저 설계도를 그려 방과 층을 만들고, 그다음 사람과 짐이 들어오고 나가며, 출입 카드로 누가 어느 층에 들어갈지 정합니다. SQL도 같습니다. 구조를 만드는 문, 데이터를 넣고 바꾸는 문, 권한을 정하는 문이 따로 있습니다.
SQL(Structured Query Language)은 관계형 데이터베이스와 소통하는 표준 언어로, 1986년 ANSI와 1987년 ISO가 표준으로 정했습니다. 다만 데이터베이스 제품마다 표준에 고유 기능을 더한 방언(dialect)을 씁니다.
| 방언 | 사용하는 데이터베이스 | |------|------| | Transact-SQL (T-SQL) | SQL Server, Azure SQL Database, Azure SQL Managed Instance, SQL Server on Azure VM | | PL/pgSQL | PostgreSQL | | PL/SQL | Oracle |
시험 팁: "Azure SQL Database와 SQL Managed Instance에서 쓰는 SQL 방언" → Transact-SQL(T-SQL). "SQL 표준을 정한 기관" → ANSI와 ISO.
---
DDL·DML·DCL, 그리고 TCL
Microsoft Learn은 SQL 문을 DDL, DML, DCL 세 그룹으로 나눕니다. 시험 문제에는 트랜잭션을 다루는 TCL이 함께 나오기도 하니 네 가지를 한 번에 정리해 두세요.
!SQL 문 유형 한눈에 보기
DDL: 구조를 정의하는 문
DDL(Data Definition Language)은 테이블, 뷰, 저장 프로시저 같은 데이터베이스 개체를 만들고, 바꾸고, 없앱니다. CREATE, ALTER, DROP, RENAME이 대표적이고, T-SQL 문서는 TRUNCATE TABLE도 DDL로 분류합니다. DROP은 개체를 영구히 지우므로 백업이 없으면 테이블의 모든 행도 함께 사라집니다.
이 예시에서 PRIMARY KEY는 행을 고유하게 식별하는 열, NOT NULL은 반드시 값이 있어야 하는 필수 열을 뜻합니다.
DML: 행 데이터를 다루는 문
DML(Data Manipulation Language)은 테이블의 행을 조회하고(SELECT), 추가하고(INSERT), 수정하고(UPDATE), 삭제합니다(DELETE). SELECT·UPDATE·DELETE는 기본적으로 모든 행에 적용되므로 보통 WHERE 절로 대상을 좁힙니다. SQL에는 "정말 실행할까요?" 같은 확인 절차가 없어서, WHERE 없는 UPDATE나 DELETE는 테이블 전체를 바꾸거나 지웁니다.
DCL: 권한을 관리하는 문
DCL(Data Control Language)은 사용자나 그룹에 권한을 주거나(GRANT), 거부하거나(DENY), 이전에 준 권한을 회수합니다(REVOKE). 주로 데이터베이스 관리자가 사용합니다.
TCL: 트랜잭션을 확정하거나 취소하는 문
TCL(Transaction Control Language)은 여러 작업을 하나의 트랜잭션으로 묶어 COMMIT으로 확정하거나 ROLLBACK으로 되돌립니다. T-SQL에서는 BEGIN TRANSACTION으로 시작하고 SAVE TRANSACTION으로 중간 저장점을 둡니다. 계좌 이체처럼 출금과 입금이 함께 성공하거나 함께 취소되어야 하는 작업에 씁니다.
| 분류 | 하는 일 | 대표 명령 | 시험 키워드 | |------|------|------|------| | DDL | 개체 구조를 정의·변경·삭제 | CREATE, ALTER, DROP, RENAME, TRUNCATE TABLE | 테이블 생성, 열 추가, 구조 변경 | | DML | 행 데이터를 조회·추가·수정·삭제 | SELECT, INSERT, UPDATE, DELETE | 데이터 조회, 행 추가, 값 수정 | | DCL | 권한을 부여·거부·회수 | GRANT, DENY, REVOKE | 권한, 액세스 허용 | | TCL | 트랜잭션을 확정·취소 | COMMIT, ROLLBACK, SAVE TRANSACTION | 확정, 되돌리기 |
시험 팁: "기존 테이블에 열을 추가한다" → ALTER(DDL). "사용자에게 SELECT 권한을 준다" → GRANT(DCL). "COMMIT과 ROLLBACK" → TCL이지 DCL이 아닙니다. 이름이 비슷한 DDL과 DCL, DML을 헷갈리게 하는 보기가 자주 나옵니다.
---
조회 문은 어떤 순서로 처리될까?
SELECT 문은 쓰는 순서와 데이터베이스가 처리하는 순서가 다릅니다. 처리 순서를 알면 WHERE와 HAVING처럼 비슷한 절의 차이가 바로 보입니다.
| 처리 순서 | 절 | 역할 | |------|------|------| | 1 | FROM (JOIN 포함) | 어느 테이블에서 가져올지 | | 2 | WHERE | 집계 전에 행을 거름 | | 3 | GROUP BY | 같은 값끼리 묶음 | | 4 | HAVING | 집계 결과(그룹)를 거름 | | 5 | SELECT | 반환할 열과 계산 | | 6 | ORDER BY | 결과를 정렬 (기본 오름차순 ASC, 내림차순 DESC) |
GROUP BY와 함께 쓰는 집계 함수는 COUNT(개수), SUM(합계), AVG(평균), MIN(최솟값), MAX(최댓값) 다섯 가지를 기억하면 됩니다. ORDER BY가 없으면 결과 행의 순서는 보장되지 않습니다.
개체 이름은 점(.)으로 범위를 좁혀 가며 씁니다. SQL Server 계열에서는 데이터베이스.스키마.테이블(예: SalesDB.dbo.Customer) 순서입니다.
시험 팁: "집계하기 전에 행을 거른다" → WHERE. "집계한 그룹을 조건으로 거른다" → HAVING. "결과를 정렬한다" → ORDER BY.
---
제약 조건: 잘못된 데이터를 막는 규칙
공연장 입구의 규칙을 생각해 보세요. 표가 있어야 하고(NOT NULL), 같은 좌석 번호는 한 명만 쓰고(UNIQUE), 실제로 판매된 표여야 하며(FOREIGN KEY), 연령 제한도 지켜야 합니다(CHECK). 제약 조건은 데이터베이스가 이런 규칙을 자동으로 지키게 하는 장치입니다.
| 제약 조건 | 하는 일 | NULL | 테이블당 개수 | |------|------|------|------| | PRIMARY KEY | 각 행을 고유하게 식별 | 허용 안 함 | 1개 | | FOREIGN KEY | 다른 테이블의 기본 키(또는 UNIQUE 열)만 참조 | 허용 | 여러 개 | | UNIQUE | 열 값의 중복을 막음 | SQL Server는 열당 NULL 1개만 허용 | 여러 개 | | NOT NULL | 값이 반드시 있어야 함 | 허용 안 함 | 여러 개 | | CHECK | 값이 조건을 만족해야 함 (예: Price >= 0) | NULL은 UNKNOWN이라 통과 | 여러 개 | | DEFAULT | 값을 생략하면 기본값을 넣음 | 해당 없음 | 열마다 1개 |
몇 가지는 따로 기억해 두세요.
복합 키: 한 열로는 행을 구분할 수 없을 때 두 개 이상의 열을 묶어 기본 키로 씁니다. 주문 번호와 줄 번호, 항공편 번호와 좌석 번호가 대표적인 예입니다. 참조 동작: 부모 행이 삭제될 때 자식 행을 함께 지우거나(ON DELETE CASCADE) 외래 키를 NULL로 바꾸도록(SET NULL) 정할 수 있습니다. 자기 참조 관계: 직원 테이블의 관리자 ID가 같은 테이블의 직원 ID를 가리키는 것처럼, 외래 키가 자기 테이블의 기본 키를 참조해 계층을 표현합니다.
시험 팁: "기본 키 vs UNIQUE" → 둘 다 중복을 막지만 기본 키는 NULL을 허용하지 않고 테이블에 하나뿐입니다. "가격이 0 이상이어야 한다" → CHECK.
---
세 가지 무결성과 NULL
무결성은 데이터가 정확하고 일관되게 유지되는 상태입니다. 관계형 데이터베이스는 제약 조건으로 세 가지 무결성을 지킵니다.
| 무결성 | 의미 | 지키는 방법 | |------|------|------| | 엔터티 무결성 | 모든 행이 고유하게 식별된다 | 기본 키 (중복 불가, NULL 불가) | | 참조 무결성 | 테이블 간 관계가 항상 유효하다 | 외래 키 (부모에 없는 값 금지) | | 도메인 무결성 | 열 값이 허용 범위 안에 있다 | 데이터 형식, CHECK, NOT NULL, DEFAULT |
참조 무결성이 없으면 존재하지 않는 고객을 가리키는 주문, 즉 부모 없는 고아 레코드가 생깁니다. 외래 키 제약은 이런 행이 들어오는 것을 막고, 자식 행이 참조 중인 부모 행을 지우려 할 때도 막거나 함께 처리합니다. 비관계형 데이터베이스는 대개 외래 키 제약을 지원하지 않아 이런 일관성을 애플리케이션이 직접 관리해야 합니다.
NULL은 0도 빈 문자열도 아니다
NULL은 값이 없거나 알 수 없는 상태를 나타내는 표시입니다. 숫자 0이나 길이가 0인 문자열('')은 실제로 존재하는 값이라 NULL과 다릅니다. NULL과의 비교는 참도 거짓도 아닌 UNKNOWN이 되므로, NULL인 행을 찾을 때는 = NULL이 아니라 IS NULL 또는 IS NOT NULL을 씁니다.
시험 팁: "주문 테이블에 고객 테이블에 없는 고객 ID가 들어가지 못하게 한다" → 참조 무결성(외래 키). "기본 키는 NULL일 수 없다" → 엔터티 무결성. "값이 없는 행을 찾는 조건" → IS NULL.
---
인덱스 유형과 비정규화의 트레이드오프
클러스터형 vs 비클러스터형 인덱스
인덱스는 책 뒤의 색인처럼 원하는 행을 빨리 찾게 해 줍니다. SQL Server 계열 데이터베이스에는 두 종류가 있습니다.
| 구분 | 클러스터형 인덱스 | 비클러스터형 인덱스 | |------|------|------| | 구조 | 테이블의 행 자체를 키 순서로 정렬해 저장 | 정렬된 키 + 실제 행을 가리키는 포인터를 별도로 저장 | | 테이블당 개수 | 1개 (행은 한 가지 순서로만 저장 가능) | 여러 개 | | 자동 생성 | 기본 키를 만들 때 (클러스터형이 아직 없으면) | UNIQUE 제약을 만들 때 | | 비유 | 사전처럼 내용 자체가 가나다순 | 책 뒤의 색인 |
인덱스는 조회를 빠르게 하지만 공짜가 아닙니다. 저장 공간을 쓰고, 행을 추가·수정·삭제할 때마다 인덱스도 함께 갱신해야 하므로 쓰기 작업이 느려질 수 있습니다. 행이 몇 개 안 되는 테이블에서는 인덱스를 써도 별 이득이 없습니다.
정규화 vs 비정규화
정규화는 중복을 줄여 쓰기와 무결성에 유리하고, 비정규화는 일부러 중복을 허용해 JOIN을 줄이고 읽기를 빠르게 합니다.
| 구분 | 정규화 | 비정규화 | |------|------|------| | 중복 | 최소화 | 일부러 허용 | | JOIN | 많아짐 | 줄어듦 | | 유리한 작업 | 쓰기, 무결성 유지 | 읽기, 보고서 | | 주된 쓰임 | OLTP 트랜잭션 시스템 | 데이터 웨어하우스, 분석 모델 |