2. 핵심 원리
2.1 NULL 대체 함수 계보
| 함수 | 지원 DB | 인자 수 | 역할 |
|---|---|---|---|
| NVL(a, b) | Oracle·Tibero | 2 | NULL 대체 |
| NVL2(a, b, c) | Oracle·Tibero | 3 | NULL 여부로 다른 값 선택 |
| IFNULL(a, b) | MySQL | 2 | NULL 대체 |
| ISNULL(a, b) | MSSQL | 2 | NULL 대체 |
| ISNULL(x) | MySQL | 1 | NULL 판별(1/0) |
| COALESCE(a, b, ...) | 표준(전체) | 2개 이상 | 첫 NULL 아닌 값 |
| NULLIF(a, b) | 표준(전체) | 2 | a=b 면 NULL |
핵심이름이 DB 마다 다른 NVL·IFNULL·ISNULL 대신 표준인 COALESCE 를 기본으로 쓰면, DB 를 옮길 때 문법을 바꿀 일이 없습니다. NVL2 처럼 표준에 없는 기능만 방언 함수를 씁니다.
같은 이름 "ISNULL"이라도 MySQL 과 MSSQL 은 완전히 다른 함수를 가리킵니다. MySQL 의 ISNULL(x) 는 인자 1개짜리 판별 함수로 NULL 이면 1, 아니면 0을 반환하고, MSSQL 의 ISNULL(a, b) 는 인자 2개짜리 대체 함수로 NVL·IFNULL 과 같은 역할입니다. 4절에서 두 함수를 각각 실행해 차이를 확인합니다.
2.2 COALESCE: 여러 인자 중 첫 값
COALESCE(a, b, c, ...) 는 인자를 왼쪽부터 순서대로 봐서 NULL 이 아닌 첫 값을 반환합니다. 인자를 2개로 제한하는 NVL·IFNULL·ISNULL 과 달리 개수 제한이 없어, 우선순위가 있는 여러 값 중 하나를 고를 때 편합니다.
Oracle 의 NVL 은 두 인자를 항상 모두 평가하지만, COALESCE 는 앞에서 NULL 아닌 값이 나오면 뒤의 인자를 평가하지 않는 단락 평가입니다. 뒤 인자에 비용이 큰 서브쿼리나 함수 호출이 있다면 COALESCE 가 더 유리할 수 있습니다.
2.3 NULLIF: 특정 값을 NULL 로
NULLIF(a, b) 는 반대 방향입니다. a 와 b 가 같으면 NULL 을 반환하고, 다르면 a 를 그대로 반환합니다. 가장 흔한 용도는 0 으로 나누는 오류를 막는 것으로, NULLIF(분모, 0) 은 분모가 0 일 때만 NULL 로 바꿔 나눗셈 결과를 오류 대신 NULL 로 만듭니다.
팁
분자 / NULLIF(분모, 0)은 실무에서 자주 쓰는 관용구입니다. 분모가 0 이면 오류 대신 NULL 이 나오므로, 화면에서는 COALESCE 로 한 번 더 감싸 "0%"나 "-" 같은 값으로 바꿔 보여줍니다.
2.4 집계 함수는 NULL 을 무시한다
COUNT(*) 는 NULL 을 포함해 모든 행을 세지만, COUNT(컬럼) 은 그 컬럼이 NULL 인 행을 빼고 셉니다. AVG·SUM·MAX·MIN 도 마찬가지로 NULL 인 행을 계산에서 제외합니다.
이 때문에 AVG(컬럼) 과 AVG(COALESCE(컬럼, 0)) 은 다른 값이 나옵니다. 앞은 NULL 행을 나눗셈의 분모에서 빼고, 뒤는 NULL 을 0 으로 바꿔 분모에 포함시키기 때문입니다. "NULL 행도 0 점으로 반영해야 하는가"는 업무 규칙에 따라 다르므로, 둘 중 무엇을 쓸지는 요구사항을 먼저 확인해야 합니다.
주의COALESCE(컬럼, 0) 을 습관적으로 AVG 안에 넣으면 평균이 낮아집니다. "담당자 없는 행은 평가에서 제외"가 맞는지 "0점으로 반영"이 맞는지는 SQL 이 아니라 업무 규칙이 정합니다.
2.5 ORDER BY 에서 NULL 의 위치
표준 SQL 은 정렬에서 NULL 을 가장 크거나 가장 작은 값으로 취급하도록 허용하되, 기본값은 DB 마다 다릅니다. Oracle 은 오름차순에서 NULL 을 마지막(가장 큰 값)으로 두고, MySQL·MSSQL 은 오름차순에서 NULL 을 처음(가장 작은 값)으로 둡니다.
표준 SQL 은 ORDER BY 컬럼 NULLS FIRST·NULLS LAST 로 위치를 직접 지정하는 문법도 정의합니다. Oracle 은 이 문법을 지원하지만 MySQL·MSSQL 은 지원하지 않아, CASE WHEN 컬럼 IS NULL THEN 1 ELSE 0 END 을 정렬 키 앞에 추가하는 방식으로 대체합니다.
2.6 문자열 연결과 NULL
표준 SQL 의 문자열 연결 연산자 || 는 NULL 이 하나라도 섞이면 전체 결과가 NULL 입니다. '김' || NULL 은 '김' 이 아니라 NULL 입니다. 연결할 값 중 NULL 이 있을 수 있는 컬럼은 COALESCE 로 먼저 빈 문자열로 바꾼 뒤 연결해야 안전합니다.
DB 마다 이 규칙에 예외가 있습니다. Oracle 은 앞서 본 것처럼 빈 문자열을 NULL 로 취급하면서도, || 연산에서는 반대로 NULL 을 빈 문자열처럼 다뤄 나머지 값이 살아남습니다. 4절에서 DB 별 함수 차이를 직접 실행해 비교합니다.