DB 기초: Oracle WHERE절 완전 정리

발라·2025년 7월 17일

서버 이해 첫걸음

목록 보기
6/11
post-thumbnail

오라클은 DB 중에서 학습용 계정을 제공하는 DB라서 공부할 때에 쓰기 편하다는 사실!

Oracle DB 연습할 때 제일 많이 쓰는 샘플 중 하나가 HR 스키마의 EMPLOYEES 테이블이지? 오늘은 이 테이블을 가지고 WHERE 절에서 자주 쓰는 비교·논리·패턴·NULL 처리를 한눈에 정리해볼게요. 실습용 코드 + 흔한 실수 + 안전한 Oracle 스타일까지 몽땅!

준비물 : Oracle 프로그램+학습용 계정
준비물 준비할 때에 도움이 될 게시글


목차

    1. 기본 전체 조회: SELECT * FROM EMPLOYEES (언제 쓰고 언제 피할까?)
    1. 실습 준비: EMPLOYEES 테이블(Oracle HR) 가정 스키마
    1. 숫자 vs 문자 리터럴 (묵시적 변환 피하기)
    1. 비교 연산자 (=, <>, !=, >, <, >=, <=)
    1. 논리 연산자 (AND / OR / NOT) & 우선순위
    1. 괄호의 힘: 조건 묶기 패턴
    1. 날짜 비교는 반드시 TO_DATE()로 명시!
    1. 연봉 계산 예시: SALARY*12 AS ANNSAL
    1. NULL 비교: IS NULL, IS NOT NULL
    1. 여러 값 매칭: 긴 OR → IN()
    1. NOT IN + NULL 함정
    1. 범위 비교: BETWEEN a AND b
    1. 문자열 패턴: LIKE_ / %
    1. 자주 쓰는 예제 모음 (복붙 세트)
    1. 미니 퀴즈: 이 쿼리 결과 맞춰봐!
    1. Cheat Sheet 요약표

0. 기본 전체 조회: SELECT * FROM EMPLOYEES

가장 먼저 해보는 탐색용 쿼리!

SELECT *
FROM EMPLOYEES;

언제 유용?

  • 테이블 구조/데이터 감 잡을 때 첫 확인용.
  • 소규모 데이터셋 튜토리얼.
  • 실습 시간에 "일단 다 보여줘" 상황.

왜 실무에서는 자제?

  • 불필요한 I/O: 컬럼이 많거나 LOB 컬럼 포함 시 성능 저하.
  • 스키마 변경 취약: 새 컬럼 추가되면 애플리케이션 쪽 결과셋 구조 깨질 수 있음.
  • 보안/권한: 노출되면 안 되는 민감 컬럼까지 반환.
  • 명시성 부족: 다른 개발자가 코드 읽기 어려움.

추천 패턴

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 비교 시 대문자 사용!


1. 실습 준비: EMPLOYEES 테이블(Oracle HR) 가정 스키마

대표 컬럼들:
| 컬럼 | 타입 | 설명 |
|---|---|---|
| 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 연습에는 충분!


2. 숫자 vs 문자 리터럴 (묵시적 변환 피하기)

나쁜 버전 (묵시적 문자→숫자 변환):

SELECT first_name, last_name
FROM   employees
WHERE  employee_id = '105';

좋은 버전:

WHERE employee_id = 105;

Oracle은 타입 변환을 시도하지만, 인덱스 사용 방해 + 예외 발생 위험. 항상 타입 맞춰 쓰기!


3. 비교 연산자

SELECT *
FROM   employees
WHERE  job_id = 'IT_PROG';
SELECT salary, last_name
FROM   employees
WHERE  salary <= 5000;
SELECT * FROM employees WHERE department_id <> 50; -- 또는 !=

동등, 부등, 크다/작다 등 기본 비교.


4. 논리 연산자 & 우선순위

ANDOR보다 우선순위가 높다는 걸 반드시 기억!

-- 사번 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;

5. 괄호의 힘: 조건 묶기

다음 두 쿼리는 결과가 다를 수 있어!

-- 의도 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 먼저 평가 → 의도와 다른 결과 가능.


6. 날짜 비교는 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 영향 없음. 강추!


7. 연봉 계산 예시

SELECT salary*12 AS annsal, last_name
FROM   employees;

필요하면 보너스 컬럼 합산:

SELECT salary*12 + NVL(commission_pct,0)*salary*12 AS total_annsal
FROM   employees;

8. NULL 비교

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;

NULL을 값처럼 다루고 싶다면?

NVL(phone_number,'N/A'), COALESCE, NVL2 등을 사용.


9. 여러 값 매칭: 긴 OR → IN

-- 길게 쓰면
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)과 동일하게 동작. 혼란만 생기니 넣지 말자.


10. 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
);

11. 범위 비교: BETWEEN (양 끝 포함)

SELECT salary, first_name
FROM   employees
WHERE  salary BETWEEN 10000 AND 19999;  -- >= 10000 AND <= 19999

12. 문자열 패턴: LIKE

와일드카드:

  • % : 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%';

(인덱스 고려 시 함수기반 인덱스 생성 가능.)


13. 자주 쓰는 예제 모음 (복붙 세트)

-- 직무 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____';

14. 미니 퀴즈 🙋‍♀️

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']

정답은 문장 아래에 써도 되고 댓글로 퀴즈 놀이해도 됨 ㅎㅎ


15. Cheat Sheet 요약표

목적패턴예시
전체 확인SELECT * FROM t개발/튜토리얼용
특정 값col = valuejob_id='IT_PROG'
범위BETWEEN a AND bsalary BETWEEN 10000 AND 19999
다중값IN ( ... )dept IN (30,50,90)
NULL 체크IS NULL / IS NOT NULLphone_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, NVL2
  • CASE WHEN 으로 조건별 출력
  • 서브쿼리 + EXISTS/NOT EXISTS
  • 집계 조건: HAVING
  • ROWNUM / FETCH FIRST N ROWS ONLY

작성일:2025.07.17 (제헌절!)
작성자:발라

profile
능숙한 바이브코딩을 할 수 있게 됨을 꿈꾸며

0개의 댓글