데이터베이스 개발자 Tip & 강좌

SQLER의 개발자들이 만들어가는 데이터베이스 사용자 Tip & 강좌 게시판입니다. SQL서버, Oracle, MySQL 등 여러 클라우드/오픈소스 기반 데이터베이스 개발 및 운영 관련 팁과 쿼리 노하우를 이곳에서 가장 먼저 접하실 수 있습니다. 많은 도움 되시길 바랍니다.

NULL 데이터가 포함된 데이터 사용 시 주의점

 

  • Version : SQL Server 2005, 2008, 2008R2, 2012, 2014, 2016

 

SQL Server에서 NULL은 0 값도 아니며 공백도 아닌 그냥 빈 값이다. 데이터를 조회할 때 NULL 값이 포함된 경우 사용자가 원하는 값이 조회되지 않을 수 있다. NULL이 포함된 데이터 조회시 어떻게 값이 다르게 표현되는지 알아본다.

 

실습에 사용된 옵션은 시스템 기본값인 SET ANSI_NULLS ON 상태이다.

 

아래 스크립트는 두 개의 테이블을 생성하여 #TestTableB 테이블에만 NULL값이 포함된 데이터를 입력 한다.

--Creating the first temporary table for testing

IF(OBJECT_ID('tempdb..#TestTableA') IS NOT NULL)

    DROP TABLE #TestTableA

 

CREATE TABLE #TestTableA (ID INT)

 

--Creating the second temporary table for testing

IF(OBJECT_ID('tempdb..#TestTableB') IS NOT NULL)

    DROP TABLE #TestTableB

 

CREATE TABLE #TestTableB (ID INT)

 

--Inserting data

INSERT INTO #TestTableA(ID) VALUES (1),(2),(5),(9),(3)

INSERT INTO #TestTableB(ID) VALUES (2),(7),(NULL),(9)

 

[NOT IN 주의]

쿼리는 서브쿼리를 사용하여 #TestTableB 테이블에 포함되어 있지 않는 데이터를 #TestTableA 에서 조회한다. 조회된 결과가 예상했던 결과인가? #TestTableB 테이블의 NULL 값으로 인해 빈 결과 집합을 생성한다.

--Checking the result of the query

SELECT ID FROM #TestTableA WHERE ID NOT IN (SELECT ID FROM #TestTableB)    

 

 

 

[집계 함수 사용시 주의]

NULL 값이 포함된 경우 집계 함수에서 결과가 다르게 표시될 수 있다. Count(*) 과 Count(Column) 의 조회 결과가 어떻게 다른지 알아본다. 테스트 테이블을 생성한다.

--Creating temporary table for testing

IF(OBJECT_ID('tempdb..#TestTable') IS NOT NULL)

    DROP TABLE #TestTable

GO

 

CREATE TABLE #TestTable ( ID INT )

 

Count(id), count(*)의 집계 결과를 조회한다. 결과가 다른 것을 확인할 수 있다. 집계 함수에 컬럼을 사용할 경우 NULL 값은 무시되는 것을 확인할 수 있다.

--Inserting data for testing

INSERT INTO #TestTable(ID) VALUES (1),(2),(NULL),(4)

 

SELECT COUNT(ID) AS 'The result of Count(ID)' FROM #TestTable

 

SELECT COUNT(*) AS 'The result of Count(*)' FROM #TestTable

 

 

 

--Inserting only NULLs

TRUNCATE TABLE #TestTable

 

INSERT INTO #TestTable(ID) VALUES (NULL),(NULL),(NULL),(NULL)

 

SELECT COUNT(ID) AS 'The result of Count(ID) when ID column contains only NULL values' FROM #TestTable

 

SELECT COUNT(*) AS 'The result of Count(*) when ID column contains only NULL values' FROM #TestTable

 

 

 

--Min , Max, AVG

TRUNCATE TABLE #TestTable

 

INSERT INTO #TestTable(ID) VALUES (1),(2),(NULL),(4),(5)

 

SELECT AVG(ID) AS Average FROM #TestTable

 

 

 

[변수 사용시 주의]

SET을 사용하여 변수에 값을 할당 할 때 SELECT 방법에 따라 결과 값이 다르게 나타난다.

DECLARE @var INT= 0

 

--Creating temporary table for testing

IF(OBJECT_ID('tempdb..#TestTable') IS NOT NULL)

    DROP TABLE #TestTable

 

CREATE TABLE #TestTable (ID INT)

 

--Inserting data for testing

INSERT INTO #TestTable(ID) VALUES (1),(2),(4)

 

--Using SELECT

SELECT @var=ID FROM #TestTable WHERE ID=3

 

SELECT @var AS 'Variable value after SELECT'

 

--Using SET

SET @var = ( SELECT ID FROM #TestTable WHERE ID=3 )

 

SELECT @var AS 'Variable value after SET'

 

 

 

DECLARE @var1 INT, @var2 INT=7

 

SET @var2 = @var1 + @var2

 

SELECT @var2 As Variable2    

 

 

 

[Group by 주의]

NULL을 포함한 그룹화에 NULL 값은 결과 집합의 하나로 포함된다.

IF(OBJECT_ID('tempdb..#TestTable') IS NOT NULL)

    DROP TABLE #TestTable

GO

 

CREATE TABLE #TestTable ( ID INT, Value INT )

 

INSERT INTO #TestTable(ID, Value) VALUES (1, 10),(2, 20),(NULL, 70),(NULL, 90),(4, 50),(5, 60)

 

SELECT ID, AVG(Value) AS Average, MAX(Value) As Maximum

FROM #TestTable

GROUP BY ID    

 

 

 

[<> (!=) 비교]

비교 연산자의 경우 대부분 NULL 값과 상수 비교 시 동일하지 않기 때문에 아래 결과가 ture 일거라고 생각한다. 하지만 알 수 없는 값과 비교 시 항상 false를 반환한다. (SET ANSI_NULLS OFF 경우 결과는 다르게 나타난다.)

 

DECLARE @a INT=1,

@b INT

 

SELECT @a AS a, @b AS b

 

IF(@a <> @b)

    SELECT 1 AS result

ELSE

    SELECT 0 AS result

 

 

 

NULL 작업을 할 때 일부 혼란스러운 경우가 있으므로 반드시 NULL 데이터 여부를 확인하고 원하는 값을 조회 할 수 있도록 특성을 파악해서 사용하는 것이 중요하다.

 

 

[참고자료]

https://www.mssqltips.com/sqlservertip/4082/some-tricky-situations-when-working-with-sql-server-nulls/

 




강성욱 / jevida@naver.com
Microsoft SQL Server MVP
Blog : http://sqlmvp.kr
Facebook : http://facebook.com/sqlmvp

No. Subject Author Date Views
2050 In-Memory OLTP 환경에서 체크포인트 작업과 디스크 부족 경고 jevida(강성욱) 2017.01.11 1273
2049 Spool 연산자와 추적 플래그 8690 jevida(강성욱) 2017.01.11 1816
2048 .NET 4.6.1에 변경된 Multisubnet 기본 수신기 동작 jevida(강성욱) 2017.01.11 1594
2047 함수 통계 정보 확인 (sys.dm_exec_function_stats) jevida(강성욱) 2017.01.11 1561
» NULL 데이터가 포함된 데이터 사용 시 주의점 jevida(강성욱) 2017.01.11 2808
2045 통계정보와 실제 데이터 분포 확인하기 jevida(강성욱) 2017.01.11 1664
2044 SQL Server Failover Cluster 설치시 네트워크 이름으로 인한 설치 오류 jevida(강성욱) 2017.01.11 1456
2043 SSIS 실행 로그 남기기 jevida(강성욱) 2017.01.11 2643
2042 확장이벤트를 사용한 실행 계획 캡처 jevida(강성욱) 2017.01.11 1208
2041 테이블 외래키 트리 확인 및 데이터 삭제하기 jevida(강성욱) 2017.01.11 1738
2040 기본 추적을 사용한 SQL Server 스키마 변경사항 캡처 jevida(강성욱) 2017.01.11 1551
2039 SQL Server 특정 테이블의 모든 컬럼에서 문자열 찾기 jevida(강성욱) 2017.01.11 1648
2038 SQL Server 임시 테이블 특성 jevida(강성욱) 2017.01.11 7090
2037 트리거를 사용하여 특정 컬럼 업데이트 하기 (After 트리거) jevida(강성욱) 2017.01.11 2128
2036 컬럼스토어 인덱스 성능 (Columnsotre Index Performance) jevida(강성욱) 2017.01.11 3150
2035 In-Memory 최적화 파일 경로 변경 jevida(강성욱) 2017.01.11 1492
2034 SA 계정 이름 변경 및 비활성화 jevida(강성욱) 2017.01.11 2264
2033 SQL Server 데이터베이스 속성을 확인할 때 사용되는 master.dbo.spt_values 복구 jevida(강성욱) 2017.01.11 1521
2032 XML로 생성된 정보를 테이블로 저장하기(sp_xml_preparedocument) jevida(강성욱) 2017.01.11 2165
2031 SQL Server 2016 Temporal Table – 데이터 변경 내용 추적 jevida(강성욱) 2017.01.11 1908





XE Login