정보처리기사 실기에서 SQL은 매 회차 반드시 출제되는 핵심 파트입니다. 다행히 나오는 유형이 어느 정도 정해져 있어서, 패턴만 잡으면 확실하게 점수를 챙길 수 있어요. 이 글에서는 실제 시험에 나오는 SQL 유형을 처음부터 차근차근 정리해드릴게요.
SQL 관련 문제는 실기 배점의 약 20~30%를 차지합니다. DDL·DML·DCL 개념 서술부터 직접 쿼리를 작성하거나 결과를 예측하는 문제까지 다양하게 나옵니다.
📦 SQL 명령어 4가지 분류부터 잡자
SQL은 역할에 따라 4가지로 나뉩니다. 시험에서 "다음 중 DDL에 해당하는 명령어는?" 식으로 분류 자체를 묻는 문제가 자주 나오니까 먼저 외워두세요.
| 분류 | 이름 | 대표 명령어 | 하는 일 |
|---|---|---|---|
| DDL | 데이터 정의어 | CREATE, ALTER, DROP, TRUNCATE | 테이블·구조 생성·수정·삭제 |
| DML | 데이터 조작어 | SELECT, INSERT, UPDATE, DELETE | 데이터 조회·삽입·수정·삭제 |
| DCL | 데이터 제어어 | GRANT, REVOKE | 사용자 권한 부여·회수 |
| TCL | 트랜잭션 제어어 | COMMIT, ROLLBACK, SAVEPOINT | 트랜잭션 확정·취소·저장점 |
DDL은 구조를 다루고, DML은 데이터를 다룹니다. DDL은 자동 COMMIT이 되지만, DML은 명시적으로 COMMIT해야 반영됩니다. 이 차이를 꼭 기억하세요!
🏗️ DDL — 테이블 만들고 바꾸는 명령어
DDL은 테이블의 틀(구조)을 만들거나 수정하는 명령어예요. 직접 쿼리를 쓰라는 문제보다는 문법 빈칸 채우기 형태로 자주 출제됩니다.
CREATE TABLE — 테이블 생성
CREATE TABLE 학생 (
학번 CHAR(8) PRIMARY KEY,
이름 VARCHAR(20) NOT NULL,
학과 VARCHAR(30),
학년 INT DEFAULT 1,
성적 FLOAT,
FOREIGN KEY (학과) REFERENCES 학과정보(학과명)
);
| 제약조건 | 의미 |
|---|---|
| PRIMARY KEY | 기본키 — 중복 불가 + NULL 불가 |
| FOREIGN KEY | 외래키 — 다른 테이블의 기본키 참조 |
| NOT NULL | NULL 값 입력 금지 |
| UNIQUE | 중복 불가 (NULL은 허용) |
| DEFAULT | 값을 안 넣으면 자동으로 들어가는 기본값 |
| CHECK | 특정 조건을 만족하는 값만 허용 |
ALTER TABLE — 테이블 구조 변경
-- 컬럼 추가
ALTER TABLE 학생 ADD 이메일 VARCHAR(50);
-- 컬럼 타입 변경
ALTER TABLE 학생 MODIFY 이름 VARCHAR(30);
-- 컬럼 삭제
ALTER TABLE 학생 DROP COLUMN 이메일;
-- 제약조건 추가
ALTER TABLE 학생 ADD CONSTRAINT 성적_범위 CHECK (성적 BETWEEN 0 AND 100);
DROP vs TRUNCATE vs DELETE 차이
| 명령어 | 분류 | 롤백 가능? | 결과 |
|---|---|---|---|
| DROP TABLE | DDL | ❌ 불가 | 테이블 구조 + 데이터 모두 삭제 |
| TRUNCATE | DDL | ❌ 불가 | 데이터만 전체 삭제 (구조는 유지) |
| DELETE | DML | ✅ 가능 | 조건에 맞는 행만 삭제 |
"ROLLBACK으로 복구할 수 없는 명령어는?" → DROP, TRUNCATE (DDL은 자동 COMMIT)
"테이블 구조는 남기고 데이터만 전부 지우는 명령어는?" → TRUNCATE
🔍 SELECT — 데이터 조회의 핵심
실기에서 가장 많이 나오는 부분입니다. SELECT 문의 실행 순서와 각 절의 역할을 정확히 이해해야 해요.
SELECT 실행 순서 (이게 제일 중요!)
SQL은 작성 순서와 실제 실행 순서가 다릅니다. 이걸 모르면 GROUP BY, HAVING, WHERE 문제에서 자꾸 틀려요.
기억법: "프~ 윙 그 하 셀 오(FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY)"
기본 SELECT 문법
SELECT [DISTINCT] 컬럼1, 컬럼2, ...
FROM 테이블명
WHERE 조건
GROUP BY 그룹기준컬럼
HAVING 그룹조건
ORDER BY 정렬기준 [ASC | DESC];
아래 예시 테이블로 실제 문제 느낌을 익혀봅시다.
| 📋 학생(STUDENT) 테이블 | ||||
|---|---|---|---|---|
| 학번 | 이름 | 학과 | 학년 | 성적 |
| 2021001 | 김민준 | 컴퓨터공학 | 3 | 88 |
| 2021002 | 이서연 | 정보통신 | 2 | 92 |
| 2022003 | 박지호 | 컴퓨터공학 | 2 | 75 |
| 2022004 | 최수아 | 소프트웨어 | 1 | 95 |
| 2023005 | 정우진 | 컴퓨터공학 | 1 | 82 |
WHERE — 조건 필터링
-- 성적이 85점 이상인 학생 조회
SELECT 이름, 성적
FROM 학생
WHERE 성적 >= 85;
-- 컴퓨터공학과이고 학년이 2학년 이상
SELECT *
FROM 학생
WHERE 학과 = '컴퓨터공학' AND 학년 >= 2;
-- 성적이 80~90 사이 (BETWEEN)
SELECT 이름, 성적
FROM 학생
WHERE 성적 BETWEEN 80 AND 90;
-- 학과가 컴퓨터공학 또는 정보통신 (IN)
SELECT 이름, 학과
FROM 학생
WHERE 학과 IN ('컴퓨터공학', '정보통신');
GROUP BY + HAVING — 그룹 집계
GROUP BY는 특정 컬럼 기준으로 행을 묶어서 집계함수(COUNT, SUM, AVG, MAX, MIN)를 적용할 때 씁니다. HAVING은 GROUP BY 이후의 그룹에 조건을 거는 것이고, WHERE는 그룹화 전에 개별 행에 조건을 거는 것입니다.
-- 학과별 학생 수와 평균 성적 조회
SELECT 학과, COUNT(*) AS 학생수, AVG(성적) AS 평균성적
FROM 학생
GROUP BY 학과;
-- 평균 성적이 80점 이상인 학과만 출력 (HAVING 사용)
SELECT 학과, AVG(성적) AS 평균성적
FROM 학생
GROUP BY 학과
HAVING AVG(성적) >= 80;
✔ WHERE — 개별 행(row)에 조건 → GROUP BY 전에 실행
✔ HAVING — 그룹에 조건 → GROUP BY 후에 실행
"WHERE에는 집계함수를 쓸 수 없다"는 것도 자주 출제됩니다.
집계함수 정리
| 함수 | 의미 | NULL 처리 |
|---|---|---|
| COUNT(*) | 전체 행 개수 | NULL 포함 |
| COUNT(컬럼) | 해당 컬럼 값이 있는 행 개수 | NULL 제외 |
| SUM(컬럼) | 합계 | NULL 제외 |
| AVG(컬럼) | 평균 | NULL 제외 |
| MAX(컬럼) | 최댓값 | NULL 제외 |
| MIN(컬럼) | 최솟값 | NULL 제외 |
ORDER BY — 정렬
-- 성적 내림차순 정렬 (높은 순)
SELECT 이름, 성적
FROM 학생
ORDER BY 성적 DESC;
-- 학과 오름차순, 같은 학과면 성적 내림차순
SELECT 이름, 학과, 성적
FROM 학생
ORDER BY 학과 ASC, 성적 DESC;
🔗 JOIN — 여러 테이블 합치기
JOIN은 두 개 이상의 테이블을 연결해서 하나의 결과로 보여주는 것입니다. 실기에서 결과 예측이나 쿼리 작성 문제로 자주 나옵니다.
예시로 두 테이블을 만들어 보겠습니다.
| 📋 수강(ENROLLMENT) 테이블 | ||
|---|---|---|
| 학번 | 과목코드 | 점수 |
| 2021001 | CS101 | 90 |
| 2021002 | CS101 | 85 |
| 2021001 | CS202 | 78 |
| 2099999 | CS303 | 95 |
-- INNER JOIN: 학생 테이블과 수강 테이블에서 모두 존재하는 학생만
SELECT S.이름, E.과목코드, E.점수
FROM 학생 S
INNER JOIN 수강 E ON S.학번 = E.학번;
-- LEFT JOIN: 학생 테이블 전체 (수강 안 한 학생도 포함)
SELECT S.이름, E.과목코드, E.점수
FROM 학생 S
LEFT JOIN 수강 E ON S.학번 = E.학번;
1. 기준 테이블이 어딘지 파악 (LEFT면 왼쪽이 기준)
2. ON 조건이 일치하는 행끼리 연결
3. 일치하지 않는 행은 NULL로 채움
4. 위 학번 2099999는 학생 테이블에 없으므로 INNER JOIN 결과에서 제외됨
🪆 서브쿼리 — 쿼리 안의 쿼리
서브쿼리는 SELECT 문 안에 또 다른 SELECT 문이 들어가는 형태입니다. 위치에 따라 이름이 달라지고, 시험에서도 종류를 묻는 문제가 나옵니다.
| 위치 | 이름 | 특징 |
|---|---|---|
| WHERE 절 | 중첩 서브쿼리 | 가장 자주 출제. 조건값을 동적으로 구함 |
| FROM 절 | 인라인 뷰 | 서브쿼리 결과를 임시 테이블처럼 사용 |
| SELECT 절 | 스칼라 서브쿼리 | 컬럼 자리에 단일 값 반환 |
WHERE절 서브쿼리 (가장 자주 출제)
-- 평균 성적보다 높은 학생 조회
SELECT 이름, 성적
FROM 학생
WHERE 성적 > (SELECT AVG(성적) FROM 학생);
-- 컴퓨터공학과 학생 중 최고 성적과 동일한 학생 조회
SELECT 이름, 성적
FROM 학생
WHERE 성적 = (SELECT MAX(성적) FROM 학생 WHERE 학과 = '컴퓨터공학');
IN / ANY / ALL 서브쿼리
-- IN: 서브쿼리 결과 목록 중 하나와 일치
SELECT 이름
FROM 학생
WHERE 학번 IN (SELECT 학번 FROM 수강 WHERE 과목코드 = 'CS101');
-- ALL: 서브쿼리 결과 모두보다 크거나 작은 경우
-- 모든 정보통신과 학생보다 성적이 높은 학생
SELECT 이름, 성적
FROM 학생
WHERE 성적 > ALL (SELECT 성적 FROM 학생 WHERE 학과 = '정보통신');
-- ANY: 서브쿼리 결과 중 하나라도 만족
SELECT 이름, 성적
FROM 학생
WHERE 성적 > ANY (SELECT 성적 FROM 학생 WHERE 학과 = '정보통신');
ALL은 "전부 다 이겨야 통과" → 최댓값보다 크면 ALL보다 크다
ANY는 "하나만 이겨도 통과" → 최솟값보다 크면 ANY보다 크다
> ALL ≈ > MAX(서브쿼리)> ANY ≈ > MIN(서브쿼리)
FROM절 서브쿼리 — 인라인 뷰
-- 학과별 평균 성적을 구한 뒤, 평균이 85 이상인 학과만 출력
SELECT 학과, 평균성적
FROM (SELECT 학과, AVG(성적) AS 평균성적
FROM 학생
GROUP BY 학과) AS 학과별평균
WHERE 평균성적 >= 85;
🔐 DCL — 권한 관리
DCL은 사용자에게 권한을 주거나 뺏는 명령어입니다. 개념 암기 위주로 출제됩니다.
-- GRANT: 권한 부여
GRANT SELECT, INSERT ON 학생 TO 홍길동;
GRANT ALL ON 학생 TO 홍길동 WITH GRANT OPTION;
-- ↑ WITH GRANT OPTION: 홍길동이 다른 사람에게 권한을 재부여할 수 있음
-- REVOKE: 권한 회수
REVOKE SELECT ON 학생 FROM 홍길동;
REVOKE SELECT ON 학생 FROM 홍길동 CASCADE;
-- ↑ CASCADE: 홍길동이 부여한 다른 사람 권한도 함께 회수
| 옵션 | 의미 |
|---|---|
| WITH GRANT OPTION | 받은 권한을 다른 사용자에게 재부여 가능 |
| CASCADE | 권한 회수 시 연쇄적으로 재부여된 권한도 회수 |
🔄 TCL — 트랜잭션 제어
트랜잭션은 하나의 논리적 작업 단위입니다. 은행 이체처럼 "전부 되거나 전부 안 되거나"를 보장하는 개념이에요.
-- 작업 확정
COMMIT;
-- 작업 취소 (마지막 COMMIT 시점으로 되돌아감)
ROLLBACK;
-- 저장점 설정 후 부분 취소
SAVEPOINT sp1;
-- ... 작업 ...
ROLLBACK TO sp1; -- sp1 이후 작업만 취소
✔ 원자성(Atomicity) — 전부 실행되거나 전부 취소
✔ 일관성(Consistency) — 트랜잭션 전후 데이터 일관성 유지
✔ 격리성(Isolation) — 다른 트랜잭션에 영향 받지 않음
✔ 지속성(Durability) — COMMIT된 결과는 영구 반영
🧩 실전 문제 풀어보기
위에서 배운 내용을 종합해서 아래 문제를 풀어보세요.
학생 테이블에서 학과별 학생 수를 구하되, 학생 수가 2명 이상인 학과의 학과명과 학생 수를 학생 수 내림차순으로 출력하시오.
-- 정답
SELECT 학과, COUNT(*) AS 학생수
FROM 학생
GROUP BY 학과
HAVING COUNT(*) >= 2
ORDER BY 학생수 DESC;
학생 테이블에서 이름과 성적을 조회하되, 자신이 속한 학과의 평균 성적보다 높은 학생만 출력하시오.
-- 정답 (상관 서브쿼리)
SELECT 이름, 성적, 학과
FROM 학생 A
WHERE 성적 > (SELECT AVG(성적)
FROM 학생 B
WHERE B.학과 = A.학과);
① SELECT 실행 순서를 암기하세요. FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. 이걸 모르면 HAVING과 WHERE 문제를 계속 틀립니다.
② WHERE vs HAVING 구분을 확실히 하세요. 집계함수가 조건에 있으면 HAVING, 없으면 WHERE입니다.
③ JOIN 결과는 직접 표를 그려서 확인하는 연습을 하세요. 머릿속으로 계산하려다가 실수하는 경우가 많습니다. 시험지 여백에 테이블 그리는 습관을 들이세요.