오라클은 DB 중에서 학습용 계정을 제공하는 DB라서 공부할 때에 쓰기 편하다는 사실!
Oracle DB 연습할 때 제일 많이 쓰는 샘플 중 하나가 HR 스키마의 EMPLOYEES 테이블이지? 오늘은 이 테이블을 가지고 WHERE 절에서 자주 쓰는 비교·논리·패턴·NULL 처리를 한눈에 정리해볼게요. 실습용 코드 + 흔한 실수 + 안전한 Oracle 스타일까지 몽땅!
준비물 : Oracle 프로그램+학습용 계정
준비물 준비할 때에 도움이 될 게시글
SELECT * FROM EMPLOYEES (언제 쓰고 언제 피할까?)TO_DATE()로 명시!SALARY*12 AS ANNSALIS NULL, IS NOT NULLIN()NOT IN + NULL 함정BETWEEN a AND bLIKE 와 _ / %SELECT * FROM EMPLOYEES가장 먼저 해보는 탐색용 쿼리!
SELECT *
FROM EMPLOYEES;
언제 유용?
왜 실무에서는 자제?
추천 패턴
SELECT employee_id, first_name, last_name, job_id, salary
FROM employees;
칼럼 목록 빠르게 보려면
DESC EMPLOYEES; -- SQL*Plus / SQLcl / SQL Developer
또는 데이터 딕셔너리:
SELECT column_id, column_name, data_type, data_length
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
ORDER BY column_id;
참고: Oracle은 기본적으로 대문자 오브젝트 이름 저장.
table_name비교 시 대문자 사용!
대표 컬럼들:
| 컬럼 | 타입 | 설명 |
|---|---|---|
| EMPLOYEE_ID | NUMBER | 사번 (PK) |
| FIRST_NAME | VARCHAR2 | 이름 |
| LAST_NAME | VARCHAR2 | 성 |
| JOB_ID | VARCHAR2 | 직무 코드 |
| SALARY | NUMBER | 월급 |
| HIRE_DATE | DATE | 입사일 |
| DEPARTMENT_ID | NUMBER | 부서번호 (FK) |
| PHONE_NUMBER | VARCHAR2 | 전화 |
※ 실제 HR 샘플과 약간 다를 수 있지만 WHERE 연습에는 충분!
나쁜 버전 (묵시적 문자→숫자 변환):
SELECT first_name, last_name
FROM employees
WHERE employee_id = '105';
좋은 버전:
WHERE employee_id = 105;
Oracle은 타입 변환을 시도하지만, 인덱스 사용 방해 + 예외 발생 위험. 항상 타입 맞춰 쓰기!
SELECT *
FROM employees
WHERE job_id = 'IT_PROG';
SELECT salary, last_name
FROM employees
WHERE salary <= 5000;
SELECT * FROM employees WHERE department_id <> 50; -- 또는 !=
동등, 부등, 크다/작다 등 기본 비교.
AND가 OR보다 우선순위가 높다는 걸 반드시 기억!
-- 사번 90 AND 월급 ≥ 5000
SELECT last_name, employee_id
FROM employees
WHERE employee_id = 90
AND salary >= 5000;
-- 사번 90 OR 월급 ≥ 5000
SELECT last_name, employee_id
FROM employees
WHERE employee_id = 90
OR salary >= 5000;
다음 두 쿼리는 결과가 다를 수 있어!
-- 의도 1) 부서 100 또는 (부서 50 중 연봉 ≥1만)
SELECT last_name, salary*12 AS annsal, employee_id
FROM employees
WHERE department_id = 100
OR (department_id = 50 AND salary*12 >= 10000);
-- 의도 2) (부서 100,50) 전부 중 연봉 ≥1만
SELECT last_name, salary*12 AS annsal, employee_id
FROM employees
WHERE (department_id IN (100,50))
AND (salary*12 >= 10000);
괄호 없으면 Oracle은 AND 먼저 평가 → 의도와 다른 결과 가능.
TO_DATE()로!문자 '16/02/02'는 세션 NLS에 따라 다르게 해석될 수 있음.
SELECT last_name, department_id, hire_date
FROM employees
WHERE department_id = 100
OR hire_date >= TO_DATE('2002-02-16','YYYY-MM-DD');
원하는 연도·월·일 명확히 지정하자.
날짜 리터럴 더 간단히:
DATE '2002-02-16'(ANSI)도 가능. NLS 영향 없음. 강추!
SELECT salary*12 AS annsal, last_name
FROM employees;
필요하면 보너스 컬럼 합산:
SELECT salary*12 + NVL(commission_pct,0)*salary*12 AS total_annsal
FROM employees;
NULL은 =, <> 비교 불가! 반드시 IS NULL / IS NOT NULL.
SELECT last_name, phone_number
FROM employees
WHERE phone_number IS NULL;
SELECT last_name, phone_number
FROM employees
WHERE phone_number IS NOT NULL;
NVL(phone_number,'N/A'), COALESCE, NVL2 등을 사용.
-- 길게 쓰면
WHERE department_id = 30 OR department_id = 50 OR department_id = 90;
-- IN으로 축약
WHERE department_id IN (30,50,90);
NULL을 IN에 넣으면?
WHERE department_id IN (30,50,90,NULL);
= NULL은 항상 UNKNOWN이라 무시 → 결국 (30,50,90)과 동일하게 동작. 혼란만 생기니 넣지 말자.
NOT IN + NULL 함정리스트에 NULL이 끼면 모든 비교가 UNKNOWN이 되어 행이 하나도 안 나올 수 있음.
-- 안전 (NULL 없음)
WHERE department_id NOT IN (30,50,90);
-- 위험 (NULL 포함 가능성 있을 때)
-- 실제론 아무 행도 반환 안 될 수 있음!
WHERE department_id NOT IN (SELECT department_id FROM some_table);
대안: NOT EXISTS 패턴.
WHERE NOT EXISTS (
SELECT 1 FROM some_table s
WHERE s.department_id = e.department_id
);
SELECT salary, first_name
FROM employees
WHERE salary BETWEEN 10000 AND 19999; -- >= 10000 AND <= 19999
와일드카드:
% : 0글자 이상 아무거나_ : 정확히 1글자예제들:
-- S로 시작
SELECT first_name FROM employees WHERE first_name LIKE 'S%';
-- S로 끝
SELECT first_name FROM employees WHERE first_name LIKE '%S';
-- S 포함 어디든
SELECT first_name FROM employees WHERE first_name LIKE '%S%';
-- S + 정확히 4글자 (총 5글자)
SELECT first_name FROM employees WHERE first_name LIKE 'S____';
Oracle은 기본적으로 대소문자 구분(DB 문자셋 설정에 따름). 케이스 무시 검색:
WHERE UPPER(first_name) LIKE 'S%';
(인덱스 고려 시 함수기반 인덱스 생성 가능.)
-- 직무 IT_PROG
SELECT * FROM employees WHERE job_id = 'IT_PROG';
-- 사번 105 직원 이름
SELECT first_name, last_name FROM employees WHERE employee_id = 105;
-- 월급 <= 5000
SELECT salary, last_name FROM employees WHERE salary <= 5000;
-- 부서 50 제외
SELECT * FROM employees WHERE department_id <> 50;
-- 사번 90이면서 월급 ≥5000
SELECT last_name, employee_id FROM employees
WHERE employee_id = 90 AND salary >= 5000;
-- 사번 90 또는 월급 ≥5000
SELECT last_name, employee_id FROM employees
WHERE employee_id = 90 OR salary >= 5000;
-- 부서 100 또는 입사일 ≥ 2002-02-16
SELECT last_name, department_id, hire_date
FROM employees
WHERE department_id = 100
OR hire_date >= DATE '2002-02-16';
-- 부서 100/50 중 연봉 ≥1만
SELECT last_name, salary*12 AS annsal, employee_id
FROM employees
WHERE (department_id IN (100,50)) AND (salary*12 >= 10000);
-- 전화번호 NULL / NOT NULL
SELECT last_name, phone_number FROM employees WHERE phone_number IS NULL;
SELECT last_name, phone_number FROM employees WHERE phone_number IS NOT NULL;
-- 부서 리스트
SELECT * FROM employees WHERE department_id IN (30,50,90);
SELECT * FROM employees WHERE department_id NOT IN (30,50,90);
-- 특정 직무들
SELECT job_id, last_name FROM employees WHERE job_id IN ('AD_VP','ST_MAN');
-- 급여 구간
SELECT salary, first_name FROM employees WHERE salary BETWEEN 10000 AND 19999;
-- LIKE 패턴 모음
SELECT first_name FROM employees WHERE first_name LIKE 'S%';
SELECT first_name FROM employees WHERE first_name LIKE '%S';
SELECT first_name FROM employees WHERE first_name LIKE '%S%';
SELECT first_name FROM employees WHERE first_name LIKE 'S____';
Q1. 아래 쿼리의 논리적 의미는?
SELECT * FROM employees
WHERE department_id = 100 OR department_id = 50 AND salary > 8000;
(A) 부서 100 또는 50 중 월급>8000?
(B) (부서 100 전부) + (부서 50 중 월급>8000)?
→ 정답은?
Q2. 아래 두 쿼리는 결과가 같을까?
WHERE department_id NOT IN (30,50,90);
vs
WHERE department_id <> 30
AND department_id <> 50
AND department_id <> 90;
언제 다를까? (NULL 생각!)
Q3. 다음 이름들 중 'S____' 패턴과 매칭되는 건? ['Sue','Susan','Steven','Sasha','Sung']
정답은 문장 아래에 써도 되고 댓글로 퀴즈 놀이해도 됨 ㅎㅎ
| 목적 | 패턴 | 예시 |
|---|---|---|
| 전체 확인 | SELECT * FROM t | 개발/튜토리얼용 |
| 특정 값 | col = value | job_id='IT_PROG' |
| 범위 | BETWEEN a AND b | salary BETWEEN 10000 AND 19999 |
| 다중값 | IN ( ... ) | dept IN (30,50,90) |
| NULL 체크 | IS NULL / IS NOT NULL | phone_number IS NULL |
| 제외 | NOT IN (NULL 주의) | dept NOT IN (30,50,90) |
| 패턴 | LIKE '%S%' | 이름에 S 포함 |
| 괄호 | (cond1 OR cond2) AND cond3 | 조건 우선순위 제어 |
| 날짜 | DATE 'YYYY-MM-DD' 또는 TO_DATE() | hire_date >= DATE '2002-02-16' |
NVL, COALESCE, NVL2CASE WHEN 으로 조건별 출력HAVING작성일:2025.07.17 (제헌절!)
작성자:발라