데이터베이스는 정보를 체계적으로 모아둔 거대한 창고다. 스마트폰 연락처, 게임 캐릭터의 레벨과 아이템 정보, 스트리밍 플랫폼의 추천 목록 등 우리가 일상에서 접하는 대부분의 정보는 데이터베이스에 저장되어 있다.
데이터를 직접 파일 단위로 관리하면 규모가 커질수록 다루기가 어려워진다. 이를 해결하기 위해 등장한 것이 DBMS, 즉 데이터베이스 관리 시스템이다. DBMS는 사용자가 복잡한 파일 구조를 직접 다루지 않아도 데이터를 효율적으로 저장하고 조회하고 수정할 수 있도록 처리해주는 소프트웨어다.
현재 가장 널리 사용되는 방식이다. R은 Relational, 즉 '관계형'을 뜻하며, 데이터를 행(Row)과 열(Column)로 구성된 표(Table) 형태로 저장한다. 친구 연락처를 예로 들면, '이름', '전화번호', '주소'가 열(Column)이 되고, 친구 한 명의 정보 한 줄이 행(Row)이 된다.
SQL은 DBMS에 명령을 내리기 위한 전용 언어다. 데이터 조회에는 SELECT, 추가에는 INSERT, 수정에는 UPDATE 같은 명령어를 사용한다.
SELECT는 SQL에서 가장 자주 사용하는 명령어다.
SELECT 이름, 학년
FROM 학생테이블;
위 구문은 학생테이블에서 이름과 학년 정보만 꺼내서 보여달라는 뜻이다.
조회한 데이터를 특정 기준으로 정렬할 때 사용한다.
ASC (오름차순): 점점 커지는 순서로 정렬한다. 1, 2, 3 또는 가, 나, 다 순이다. 기본값이므로 생략해도 동일하게 동작한다.DESC (내림차순): 점점 작아지는 순서로 정렬한다. 10, 9, 8처럼 큰 숫자부터 또는 최신 날짜부터 볼 때 사용한다.동일한 값이 여러 번 등장할 때 한 번씩만 표시하고 싶다면 DISTINCT를 사용한다. 예를 들어 반에 어떤 성씨가 있는지 조회할 때 '김, 김, 이, 박, 박, 최' 대신 '김, 이, 박, 최'처럼 중복 없이 보여준다.
수학에서 사용하는 비교 연산자와 동일하게 동작한다. '같지 않다'는 !=와 <> 두 가지 모두 사용할 수 있으며, SQL 표준에서는 <>를 더 많이 사용한다.
WHERE는 원하는 조건에 맞는 데이터만 걸러내는 역할을 한다.
SELECT 이름
FROM 학생테이블
WHERE 학년 = 3;
위 구문은 학생테이블에서 학년이 3인 학생만 걸러낸 뒤 이름만 보여달라는 뜻이다.
SQL의 실제 실행 순서는 FROM → WHERE → SELECT 순이다. 먼저 어느 테이블을 사용할지 결정하고, 조건에 맞는 데이터만 걸러낸 뒤, 필요한 열만 최종적으로 선택해서 보여준다.
LIKE: 패턴으로 데이터를 검색할 때 사용한다.
%: 글자 수에 상관없이 아무 문자나 허용한다. WHERE 이름 LIKE '김%'이라고 하면 김민수, 김밥, 김치볶음밥 등 김으로 시작하는 모든 값을 찾는다._: 정확히 한 글자만 대신한다. WHERE 이름 LIKE '김__'이라고 하면 김민수, 김동현처럼 세 글자인 값은 찾지만 '김밥'처럼 글자 수가 맞지 않는 값은 찾지 못한다.BETWEEN A AND B: 범위 조건을 간결하게 표현한다. 키 BETWEEN 160 AND 170이라고 하면 160 이상 170 이하인 데이터를 모두 찾는다.
IN (A, B, C): 여러 값 중 하나에 해당하는 데이터를 찾는다. WHERE 취미 IN ('축구', '농구', '야구')처럼 쓰면 OR 조건을 여러 번 쓰는 것보다 코드가 훨씬 간결해진다.
IS NULL / IS NOT NULL: NULL은 숫자 0도 아니고 빈 문자열도 아니다. 값이 아직 입력되지 않아 알 수 없는 상태를 뜻한다. 일반 비교 연산자 =로는 NULL을 찾을 수 없으므로 반드시 IS NULL 또는 IS NOT NULL을 사용해야 한다.
AND: 두 조건을 모두 만족하는 경우를 선택한다. "중학생이고 떡볶이를 좋아하는 사람"처럼 두 조건이 동시에 참이어야 한다.OR: 두 조건 중 하나 이상을 만족하는 경우를 선택한다. "중학생이거나 고등학생인 사람"처럼 둘 중 하나만 맞아도 통과된다.NOT: 조건을 반전시킨다. "민트초코를 좋아하지 않는 사람"처럼 해당 조건에 해당하지 않는 데이터를 찾는다.일반적인 프로그래밍 언어와 마찬가지로 SQL에서도 AND 연산이 OR 연산보다 우선순위가 높다. 만약 괄호 없이 team_id = 'K02' OR team_id = 'K07' AND position = 'MF'라고 작성한다면, 컴퓨터는 'K07 팀이면서 MF인 선수' 또는 'K02 팀인 모든 선수'를 조회하게 된다.
team_id IN ('K02', 'K07') 방식은 OR 연산자를 여러 번 사용하는 것보다 가독성이 훨씬 좋다. IN 연산자는 괄호 안에 나열된 값들 중 하나라도 일치하면 참(True)을 반환하므로, 팀 ID 조건을 하나로 묶어주는 효과가 있다.
IN을 통해 걸러진 'K02 또는 K07 팀에 속한 선수들'이라는 결과 집합에 대해, 다시 AND position = 'MF' 조건을 적용함으로써 최종적으로 두 가지 조건을 모두 만족하는 행만 결과로 출력된다.
| 작성 방식 | 특징 |
|---|---|
| OR 사용 | (team_id = 'K02' OR team_id = 'K07') AND ... 처럼 반드시 괄호를 써야 오작동을 막을 수 있다. |
| IN 사용 | team_id IN ('K02', 'K07') AND ... 처럼 괄호 없이도 의미가 명확하며 코드가 간결해진다. |
결론적으로 IN 연산자를 사용하면 OR의 우선순위 문제를 직관적으로 해결할 수 있다. 데이터베이스 검색 시 여러 값 중 하나를 선택해야 하는 상황에서는 IN을 활용하는 것이 유지보수와 가독성 측면에서 유리하다.
CASE 문은 SQL에서 사용하는 조건 분기 구문이다. 프로그래밍의 if-else와 동일한 역할을 한다. 특정 컬럼의 값에 따라 출력 결과를 다르게 보여주고 싶을 때 사용한다.
기본 구조는 다음과 같다.
CASE
WHEN 조건1 THEN 조건1이 참일 때 출력할 값
WHEN 조건2 THEN 조건2가 참일 때 출력할 값
ELSE 위 조건이 모두 거짓일 때 출력할 값
END
WHEN은 조건을 제시하고, THEN은 그 조건이 참일 때 반환할 값을 지정한다. ELSE는 앞선 조건이 모두 해당하지 않을 때의 기본값이다. END로 CASE 문이 끝났음을 알린다.
SELECT manager_id,
CASE
WHEN manager_id = 100 THEN '100입니다'
ELSE '100이 아닙니다'
END AS 결과
FROM employees;
실행 흐름
FROM employees: employees 테이블 전체를 불러온다.SELECT manager_id: manager_id 컬럼을 조회한다.CASE ~ END AS 결과: 각 행의 manager_id 값을 조건에 따라 판단해 '결과'라는 이름의 새 컬럼으로 출력한다.조건 판단 과정
employees 테이블의 행을 한 줄씩 읽으면서 아래와 같이 판단한다.
manager_id가 100이면 → '100입니다' 출력manager_id가 100이 아닌 모든 경우 → '100이 아닙니다' 출력출력 예시
| manager_id | 결과 |
|---|---|
| 100 | 100입니다 |
| 101 | 100이 아닙니다 |
| 100 | 100입니다 |
| 124 | 100이 아닙니다 |
AS 결과는 CASE 문 전체에 붙이는 별칭(Alias)이다. CASE 문 자체는 컬럼명이 없기 때문에, END 뒤에 AS 별칭을 붙여서 출력될 컬럼 이름을 지정해준다.
SELECT department_id,
CASE
WHEN department_id = 60 THEN 'IT부서'
WHEN department_id = 100 THEN '회계부서'
ELSE '기타부서'
END AS 결과
FROM employees
WHERE department_id IN (60, 100);
실행 흐름
FROM employees: employees 테이블 전체를 불러온다.WHERE department_id IN (60, 100): department_id가 60이거나 100인 행만 걸러낸다. 나머지 부서의 행은 이 시점에 이미 제외된다.SELECT department_id: 걸러진 행들의 department_id를 조회한다.CASE ~ END AS 결과: 남은 행들에 대해 조건을 판단하여 결과를 출력한다.조건 판단 과정
CASE 문은 WHEN 조건을 위에서 아래로 순서대로 검사한다. 먼저 참이 되는 조건에서 멈추고 해당 값을 반환한다.
department_id가 60이면 → 'IT부서' 출력 후 다음 WHEN은 검사하지 않는다.department_id가 60이 아니고 100이면 → '회계부서' 출력출력 예시
| department_id | 결과 |
|---|---|
| 60 | IT부서 |
| 60 | IT부서 |
| 100 | 회계부서 |
| 100 | 회계부서 |
두 번째 쿼리에서 중요한 개념이 하나 있다. WHERE와 CASE는 모두 조건을 다루지만 역할이 완전히 다르다.
| 구분 | 역할 |
|---|---|
| WHERE | 조회할 행 자체를 걸러낸다. 조건에 맞지 않는 행은 결과에 포함되지 않는다. |
| CASE | 행은 그대로 두고, 출력되는 값만 조건에 따라 바꾼다. |
두 번째 쿼리에서 WHERE department_id IN (60, 100)을 사용했기 때문에 결과에는 60번과 100번 부서의 행만 나온다. 따라서 CASE 문의 ELSE '기타부서' 조건은 이 쿼리에서는 실제로 실행될 일이 없다. WHERE가 이미 60과 100만 남겨두었기 때문이다.
만약 WHERE절을 제거한다면 모든 부서가 조회되고, 60번도 100번도 아닌 부서는 CASE 문의 ELSE에 의해 '기타부서'로 출력된다.