본문으로 이동
메뉴 여닫기
환경 설정 메뉴 여닫기
개인 메뉴 여닫기
로그인하지 않음
지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.
  • 상위 문서: SQL
WHERE Clause
FROM 절에서 읽은 행 가운데 조건을 만족하는 행만 남기는 SQL 절

WHERE 절은 SELECT, UPDATE, DELETE 문에서 처리할 행을 고르는 조건을 적는 곳이다. 조건식의 결과가 참(TRUE)인 행만 남고, 거짓(FALSE)이나 알 수 없음(UNKNOWN)인 행은 버려진다. NULL과의 비교는 UNKNOWN이 되므로 조건을 쓸 때 NULL 처리를 따로 생각해야 한다. WHERE 절이 없으면 모든 행이 대상이 된다.

B_EMP

사원번호 이름 부서번호 관리자번호 급여 입사일 커미션
1001 김대표 10 NULL 9000 2015-01-05 NULL
1002 이부장 20 1001 6000 2017-03-15 NULL
1003 박과장 20 1002 4500 2019-07-01 NULL
1004 최대리 30 1001 4000 2020-11-20 500
1005 정사원 30 1004 3000 2022-02-28 0
1006 한신입 NULL 1002 2500 2024-08-01 NULL

연산자의 종류

편집 원본 편집
구분 연산자 의미
비교 연산자 =, >, >=, <, <= 같다, 크다, 크거나 같다, 작다, 작거나 같다
<>, !=, ^= 같지 않다. 세 가지 모두 Oracle에서 쓸 수 있으며 표준은 <>이다.
SQL 연산자 BETWEEN a AND b a 이상 b 이하(양 끝 포함)
IN (목록) 목록 값 중 하나와 같다
LIKE '패턴' 문자 패턴과 일치한다. %는 0개 이상의 아무 문자, _는 정확히 1개의 아무 문자
IS NULL 값이 NULL이다
논리 연산자 NOT, AND, OR 부정, 그리고, 또는
부정 연산자 NOT BETWEEN a AND b a 미만이거나 b 초과
NOT IN (목록), IS NOT NULL 목록 값 모두와 다르다, NULL이 아니다
조건 결과 행 설명
급여 BETWEEN 3000 AND 4500 박과장, 최대리, 정사원 4500과 3000도 포함된다.
급여 BETWEEN 4500 AND 3000 0행 급여 >= 4500 AND 급여 <= 3000과 같아서 작은 값을 앞에 써야 한다.
급여 NOT BETWEEN 3000 AND 4500 김대표, 이부장, 한신입
부서번호 IN (10, 30) 김대표, 최대리, 정사원 부서번호 = 10 OR 부서번호 = 30과 같다.
이름 LIKE '%장' 이부장, 박과장 '장'으로 끝나는 이름
이름 LIKE '_대%' 김대표, 최대리 두 번째 글자가 '대'인 이름
부서번호 IS NULL 한신입
부서번호 = NULL 0행 NULL과의 비교는 UNKNOWN이므로 IS NULL을 써야 한다.
부서번호 <> 20 김대표, 최대리, 정사원 부서번호가 NULL인 한신입은 포함되지 않는다. !=, ^=, NOT 부서번호 = 20도 결과가 같다.
커미션 IS NOT NULL 최대리, 정사원 커미션 0은 NULL이 아니다.

%나 _ 문자 자체를 찾으려면 ESCAPE로 지정한 문자를 앞에 붙인다.

SELECT 'A_1' FROM DUAL WHERE 'A_1' LIKE 'A\_%' ESCAPE '\';   -- 1행: '_' 문자 자체와 일치
SELECT 'AB1' FROM DUAL WHERE 'AB1' LIKE 'A\_%' ESCAPE '\';   -- 0행
SELECT 'AB1' FROM DUAL WHERE 'AB1' LIKE 'A_%';               -- 1행: '_'가 아무 문자 1개

연산자 우선순위

편집 원본 편집
순위 연산자
1 괄호 ( )
2 비교 연산자, SQL 연산자(BETWEEN, IN, LIKE, IS NULL)
3 NOT
4 AND
5 OR

AND가 OR보다 먼저 계산되므로 괄호 유무에 따라 결과가 달라진다.

-- (1) 괄호 없음: 부서번호 = 30 OR (부서번호 = 20 AND 급여 >= 5000)
SELECT 이름, 부서번호, 급여 FROM B_EMP
WHERE 부서번호 = 30 OR 부서번호 = 20 AND 급여 >= 5000;

-- (2) 괄호 있음
SELECT 이름, 부서번호, 급여 FROM B_EMP
WHERE (부서번호 = 30 OR 부서번호 = 20) AND 급여 >= 5000;
쿼리 결과 행 수
(1) 괄호 없음 이부장(20, 6000), 최대리(30, 4000), 정사원(30, 3000) 3
(2) 괄호 있음 이부장(20, 6000) 1
  • (1)에서는 30번 부서 사원이 급여와 상관없이 모두 나온다.
  • NOT 부서번호 = 20 AND 급여 >= 4000은 (NOT 부서번호 = 20) AND 급여 >= 4000으로 처리되어 김대표, 최대리 2행이 나온다.

문자 비교 규칙

편집 원본 편집

Oracle은 비교하는 두 값의 형식에 따라 문자열을 다르게 비교한다.

경우 비교 방법
양쪽이 CHAR(또는 문자 리터럴) 짧은 쪽 끝에 공백을 채워 길이를 맞춘 뒤 비교한다. 뒤 공백만 다르면 같다.
한쪽이라도 VARCHAR2 공백을 채우지 않고 그대로 비교한다. 뒤 공백도 문자로 친다.
문자와 숫자 문자를 숫자로 바꾸어 비교한다(암시적 형변환).

CHAR(5) 칼럼 C와 VARCHAR2(5) 칼럼 V에 'AB'와 'AB '(뒤 공백 1개)를 넣은 테이블로 확인한 결과이다. C에는 길이 5로 공백이 채워져 저장된다.

조건 일치 행 수 이유
C = 'AB' 2 CHAR와 리터럴이므로 공백 패딩 비교
V = 'AB' 1 VARCHAR2는 'AB '(공백 포함)와 'AB'를 다르게 본다.
C = V 0 'AB '(CHAR)와 'AB', 'AB '(VARCHAR2)를 공백 패딩 없이 비교
'AB' = 'AB ' 1 리터럴끼리는 CHAR 비교

NOT IN 목록에 NULL이 하나라도 있으면 결과는 0행이다. 부서번호 NOT IN (20, NULL)은 부서번호 <> 20 AND 부서번호 <> NULL이고, 부서번호 <> NULL은 항상 UNKNOWN이기 때문이다. 반면 IN (20, NULL)은 OR로 풀리므로 20번 부서 2행이 정상으로 나온다. 서브쿼리 결과에 NULL이 섞일 때 같은 문제가 생긴다(데이터베이스 Null, 데이터베이스 서브 쿼리).

조건 결과
부서번호 NOT IN (20) 김대표, 최대리, 정사원(3행)
부서번호 NOT IN (20, NULL) 0행
부서번호 IN (20, NULL) 이부장, 박과장(2행)

WHERE 절과 집계 함수

편집 원본 편집

WHERE 절은 그룹을 만들기 전의 개별 행에 적용되므로 집계 함수를 쓸 수 없다. 그룹 조건은 HAVING 절에 쓴다(SQL 그룹 함수).

SELECT 부서번호 FROM B_EMP WHERE AVG(급여) >= 5000 GROUP BY 부서번호;
-- ORA-00934: group function is not allowed here

SELECT 부서번호, AVG(급여) FROM B_EMP
GROUP BY 부서번호
HAVING AVG(급여) >= 5000;     -- 10번(9000), 20번(5250)

Oracle의 ROWNUM은 WHERE 절을 통과한 행에 1부터 차례로 붙는 번호이다. WHERE ROWNUM <= 3은 3행을 돌려주지만 WHERE ROWNUM = 2는 0행이다. 첫 행이 ROWNUM 1을 받자마자 조건(=2)에서 탈락해 다음 행이 다시 1이 되기 때문이다. 정렬한 뒤 상위 N개를 고르는 방법은 Top N 쿼리에서 다룬다.

실행 순서와 별칭

편집 원본 편집

SELECT 문은 적힌 순서가 아니라 다음 순서로 논리적으로 처리된다.

순서 1 2 3 4 5 6
절 FROM WHERE GROUP BY HAVING SELECT ORDER BY

WHERE 절은 SELECT 절보다 먼저 처리되므로 SELECT 절에서 붙인 별칭을 WHERE 절에서 쓸 수 없다.

SELECT 이름, 급여*12 AS 연봉 FROM B_EMP WHERE 연봉 >= 50000;
-- ORA-00904: "연봉": invalid identifier

SELECT 이름, 급여*12 AS 연봉 FROM B_EMP WHERE 급여*12 >= 50000;   -- 식을 다시 쓴다
  • ORDER BY 절은 SELECT 다음에 처리되므로 별칭을 쓸 수 있다(SQL ORDER BY 절).
  • AND가 OR보다 먼저 계산된다. 괄호 유무에 따른 결과 행 수 차이를 묻는 문제가 자주 나온다.
  • BETWEEN은 양 끝을 포함하고, 작은 값을 앞에 써야 한다. LIKE의 %와 _ 차이, ESCAPE 사용법
  • = NULL은 결과가 없고 IS NULL을 써야 한다. NOT IN 목록에 NULL이 있으면 0행이다. <> 조건에서 NULL 행은 빠진다.
  • CHAR끼리는 공백을 채워 비교하고, VARCHAR2가 끼면 그대로 비교한다.
  • WHERE에는 집계 함수와 SELECT 별칭을 쓸 수 없다(FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY).