SQL 개발자(SQLD) 시험 노트개념 정리14 MIN
WHERE 절과 비교·논리 연산자
SQLD 2과목의 셋째 자리입니다. WHERE 절에 쓰는 비교 연산자와 부정 비교 연산자, BETWEEN·IN·LIKE와 ESCAPE, IS NULL로 NULL을 찾는 법, 그리고 AND·OR·NOT의 우선순위가 결과를 어떻게 바꾸는지 정리합니다.
앞 노트의 SELECT가 「어떤 컬럼을 볼까」였다면 WHERE는 「어떤 행을 볼까」입니다. 2과목에서 가장 많은 문항이 걸려 있는 절이고, 대부분 테이블을 주고 결과 행 수를 세게 하는 형태로 나옵니다. 그래서 연산자 이름을 외우는 것보다 주어진 데이터로 직접 세어 보는 연습이 점수가 됩니다.
이 절의 예제는 아래 사원 테이블을 씁니다.
| 사원명 | 부서코드 | 급여 | 상여 |
|---|---|---|---|
| 홍길동 | D01 | 300 | 50 |
| 김철수 | D01 | 250 | NULL |
| 이영희 | D02 | 400 | 100 |
| 박민수 | D02 | 350 | NULL |
WHERE 절과 비교 연산자
WHERE의 자리
WHERE는 FROM 다음에 옵니다. 조건이 참인 행만 결과에 남고, 거짓이거나 판단할 수 없는 행은 빠집니다.
SELECT 사원명, 급여
FROM 사원
WHERE 급여 >= 300;
-- 홍길동 300 / 이영희 400 / 박민수 350
조건에 적는 값이 문자면 작은따옴표로 감쌉니다. 숫자는 따옴표 없이 적고, 숫자 컬럼에 '300'처럼 따옴표를 붙이면 자동으로 숫자로 바뀌어 비교되지만 인덱스를 못 쓰게 되는 자리가 생깁니다.
여섯 비교 연산자
| 연산자 | 뜻 |
|---|---|
= |
같다 |
> |
크다 |
>= |
크거나 같다 |
< |
작다 |
<= |
작거나 같다 |
여기에 「같지 않다」가 붙어 여섯입니다. 문자를 비교하면 사전 순서로 크고 작음을 따지고, 날짜를 비교하면 나중 날짜가 큰 값입니다.
부정 비교 연산자
「같지 않다」는 표기가 여럿입니다. !=·^=·<>가 모두 같은 뜻이고, NOT 컬럼 = 값으로 적어도 같습니다. 표기가 다를 뿐 동작이 같다는 것을 묻는 보기가 나옵니다.
NOT을 붙이는 방식은 범위 연산자에도 그대로 적용되어 NOT BETWEEN·NOT IN·NOT LIKE가 됩니다.
범위와 목록
BETWEEN A AND B
BETWEEN A AND B는 A 이상 B 이하를 뜻합니다. 양 끝을 포함한다는 것이 핵심이고, 급여 >= A AND 급여 <= B와 같은 조건입니다.
WHERE 급여 BETWEEN 250 AND 350은 250과 350을 모두 포함하므로 김철수·홍길동·박민수 세 행이 나옵니다. 그리고 A가 B보다 크면 조건이 성립하지 않아 한 행도 안 나옵니다 — BETWEEN 350 AND 250은 오류가 아니라 빈 결과입니다.
IN
IN은 목록 안의 값 중 하나와 같은지를 봅니다. WHERE 부서코드 IN ('D01', 'D02')는 부서코드 = 'D01' OR 부서코드 = 'D02'와 같습니다. 값을 여럿 나열할 때 OR를 반복하는 것보다 짧고, 목록 자리에 서브쿼리를 넣을 수도 있습니다.
부정형과 NULL
NOT IN은 목록에 NULL이 있거나 비교되는 컬럼이 NULL이면 결과가 비어 버립니다. NULL과의 비교는 참도 거짓도 아닌 「알 수 없음」이 되고, WHERE는 참인 행만 남기기 때문입니다.
위 테이블에서 WHERE 상여 NOT IN (50, 100)을 실행하면 한 행도 안 나옵니다. 홍길동과 이영희는 목록에 있는 값이라 빠지고, 상여가 NULL인 김철수와 박민수는 판단할 수 없어 함께 빠집니다. 「상여가 50도 100도 아닌 사람」을 찾으려던 의도와 결과가 어긋나는 자리입니다.
LIKE와 와일드카드
%와 _
LIKE는 문자열의 일부만 맞아도 찾아 주는 연산자입니다. 자리를 대신하는 기호가 둘입니다.
| 기호 | 뜻 | 예 |
|---|---|---|
% |
0자 이상의 아무 문자 | '김%'은 김으로 시작하는 모든 이름 |
_ |
정확히 한 글자 | '김_수'는 김으로 시작해 한 글자를 건너 수로 끝나는 세 글자 |
_가 정확히 한 글자라는 점이 자주 틀리는 자리입니다. '김_'은 두 글자 이름만 찾고 김이라는 한 글자 이름이나 세 글자 이름은 못 찾습니다.
ESCAPE
찾으려는 값 자체에 %나 _가 들어 있으면 기호와 글자를 가를 수 없습니다. 이때 ESCAPE 문자를 정해 그 뒤에 오는 한 글자를 기호가 아닌 글자로 읽게 합니다.
SELECT 코드 FROM 상품
WHERE 코드 LIKE 'A\_%' ESCAPE '\';
-- 'A_01'은 찾고 'AB01'은 못 찾는다
ESCAPE에 적는 문자는 아무거나 정할 수 있습니다. 위에서는 역슬래시를 썼지만 ESCAPE '#'로 정하고 'A#_%'로 적어도 결과가 같습니다.
NULL을 다루는 조건
IS NULL과 IS NOT NULL
NULL은 값이 아니라 값이 없다는 표시라서 =로 찾을 수 없습니다. WHERE 상여 = NULL은 오류는 아니지만 한 행도 돌려주지 않습니다. NULL인 행을 찾으려면 IS NULL, NULL이 아닌 행을 찾으려면 IS NOT NULL을 씁니다.
SELECT 사원명 FROM 사원 WHERE 상여 IS NULL;
-- 김철수 / 박민수
SELECT 사원명 FROM 사원 WHERE 상여 IS NOT NULL;
-- 홍길동 / 이영희
두 조건은 서로 겹치지 않고 합치면 전체 행이 되므로, 결과 행 수를 세는 문항에서 검산에 쓸 수 있습니다.
알 수 없음이 만드는 결과
NULL이 낀 비교는 참도 거짓도 아닌 「알 수 없음」이 됩니다. 앞 노트의 산술 연산이 NULL에 전염되었듯 비교도 전염되지만, 결과가 NULL로 보이는 것이 아니라 그 행이 조용히 빠지는 형태로 나타납니다. WHERE 상여 > 0에 상여가 NULL인 두 행이 안 나오는 것도, NOT IN이 빈 결과를 내는 것도 모두 같은 이유입니다.
논리 연산자
NOT·AND·OR의 우선순위
조건을 여럿 묶는 연산자는 셋이고 우선순위가 NOT → AND → OR 차례입니다. AND가 OR보다 먼저 묶인다는 것이 결과를 가르는 지점입니다.
SELECT 사원명 FROM 사원
WHERE 부서코드 = 'D01' OR 부서코드 = 'D02' AND 급여 >= 400;
-- 홍길동 / 김철수 / 이영희 (3행)
AND가 먼저 묶여 「D01이거나, (D02이면서 급여가 400 이상)」으로 읽힙니다. D01인 두 명이 급여와 상관없이 다 들어오고 D02에서는 이영희만 들어옵니다.
괄호로 뜻을 고정하기
같은 조건에 괄호를 씌우면 결과가 달라집니다.
SELECT 사원명 FROM 사원
WHERE (부서코드 = 'D01' OR 부서코드 = 'D02') AND 급여 >= 400;
-- 이영희 (1행)
이번에는 「D01이거나 D02이면서, 급여가 400 이상」이라 이영희 한 명만 남습니다. 같은 문자로 이루어진 두 조건이 세 행과 한 행으로 갈리므로, 시험에서 괄호가 보이면 먼저 묶인 자리부터 표시해 두고 세는 편이 안전합니다.
연습 문제
WHERE절에 대한 설명으로 옳지 않은 것은?
①FROM다음에 온다
② 조건이 참인 행만 결과에 남는다
③ 문자 값은 작은따옴표로 감싼다
④ 조건을 판단할 수 없는 행은 결과에 남는다④. 참인 행만 남으므로 「알 수 없음」이 된 행은 빠집니다.다음 중 「같지 않다」를 뜻하지 않는 것은?
①!=
②<>
③^=
④=!④. 그런 연산자는 없습니다. 나머지 셋은 표기만 다르고 동작이 같습니다.아래 테이블에서
WHERE 급여 BETWEEN 250 AND 350의 결과 행 수는?
「(홍길동, 300), (김철수, 250), (이영희, 400), (박민수, 350)」
① 1
② 2
③ 3
④ 4③.BETWEEN은 양 끝을 포함하므로 250·300·350이 모두 들어오고 400만 빠집니다.아래 테이블에서
WHERE 상여 NOT IN (50, 100)의 결과 행 수는?
「상여는 차례로 50, NULL, 100, NULL이다」
① 0
② 1
③ 2
④ 4①. 50과 100인 행은 목록에 있어 빠지고, NULL인 두 행은 비교가 「알 수 없음」이 되어 함께 빠집니다. 「50도 100도 아닌 사람」을 찾으려면상여 IS NULL OR 상여 NOT IN (50, 100)처럼 적어야 합니다.사원 테이블에 다음 두 조건절을 각각 걸었을 때의 결과 행 수를 차례로 고르면?
「(홍길동, D01, 300), (김철수, D01, 250), (이영희, D02, 400), (박민수, D02, 350)」-- ㉠ WHERE 부서코드 = 'D01' OR 부서코드 = 'D02' AND 급여 >= 400 -- ㉡ WHERE (부서코드 = 'D01' OR 부서코드 = 'D02') AND 급여 >= 400
① ㉠ 3행, ㉡ 1행
② ㉠ 1행, ㉡ 3행
③ ㉠ 4행, ㉡ 2행
④ ㉠ 3행, ㉡ 3행①. ㉠은AND가 먼저 묶여 D01 둘과 이영희까지 세 행이고, ㉡은 괄호가 먼저라 급여 400 이상 조건이 전부에 걸려 이영희만 남습니다.LIKE에 대한 설명으로 옳은 것은?
①_는 0자 이상의 아무 문자를 뜻한다
②'김_'은김이라는 한 글자 이름도 찾는다
③'김%'은 김으로 시작하는 모든 이름을 찾는다
④LIKE는 숫자 컬럼에만 쓴다③._는 정확히 한 글자라서'김_'은 두 글자 이름만 찾습니다.코드컬럼에A_01과AB01이 있을 때A_01만 찾는 조건은?
①코드 LIKE 'A_%'
②코드 LIKE 'A\_%' ESCAPE '\'
③코드 LIKE 'A%'
④코드 = 'A_%'②.ESCAPE로 정한 문자 뒤의_는 기호가 아니라 글자로 읽힙니다. ①과 ③은 둘 다 찾고, ④는 값이 정확히A_%인 행만 찾습니다.NULL을 다루는 조건으로 옳은 것은?
①WHERE 상여 = NULL은 상여가 NULL인 행을 찾는다
②WHERE 상여 IS NULL과WHERE 상여 IS NOT NULL의 결과를 합치면 전체 행이 된다
③WHERE 상여 > 0은 상여가 NULL인 행도 찾는다
④WHERE NOT 상여 = NULL은 상여가 NULL이 아닌 행을 찾는다②. 두 조건은 겹치지 않고 전체를 나눕니다. NULL은=로 비교할 수 없어 ①과 ④는 빈 결과이고, ③은 판단할 수 없어 NULL 행이 빠집니다.
다음 자리에서는 값을 가공하는 문자·숫자·날짜 함수로 들어갑니다. 함수는 SELECT 뒤에만 쓰는 것이 아니라 WHERE의 조건 안에도 그대로 들어가므로, 이 절에서 본 비교 연산자의 양쪽에 함수가 놓인 형태가 곧바로 나옵니다. 그리고 조건에 걸린 컬럼을 함수로 감싸면 그 컬럼의 인덱스를 못 쓰게 되는 자리가 생기는데, 그 이유는 함수를 먼저 정리한 뒤에 다루는 편이 이해가 빠릅니다. 여기서는 양 끝을 포함하는 BETWEEN, 빈 결과를 내는 NOT IN, AND가 먼저 묶인다는 세 가지만 확실히 해 두고 넘어가면 됩니다.

