다음을 통해 공유


쿼리 식에서의 오류 및 경고 문제 해결

경우에 따라 SQL Server 2008에서는 SQL Server 2000보다 빨리 쿼리의 식을 평가합니다. 이 경우 다음과 같은 중요한 이점이 있습니다.

  • 계산 열 식과 같은 쿼리의 식에 계산 열의 인덱스를 일치시킬 수 있습니다.

  • 식 결과의 중복 계산을 방지합니다.

그러나 쿼리에 안전하지 않은 기존 식이 포함된 경우 쿼리 및 데이터베이스 데이터의 특성에 따라 SQL Server 2008에서 런타임 예외가 발생할 수 있습니다. 이러한 런타임 예외는 다음과 같습니다.

  • 산술 예외: 0 나누기, 오버플로 및 언더플로

  • 전체 자릿수 손실 및 숫자가 아닌 문자열을 숫자로 변환하려는 시도와 같은 변환 실패

  • Null일 수도 있는 값들의 집계

SQL Server 2000에서 특정 데이터를 사용하는 특정 응용 프로그램에서는 이러한 예외가 발생하지 않을 수도 있습니다. 그러나 통계 변경 때문에 변경되는 쿼리 계획으로 인해 SQL Server 2008에서 예외가 발생할 수 있습니다. NULLIF 또는 CASE와 같은 조건 식을 포함하도록 쿼리를 수정하면 이러한 런타임 예외를 방지할 수 있습니다.

중요 정보중요

검색 조건, SELECT 목록 또는 쿼리 내 기타 위치에 나타나는 식을 나누어 하나 이상의 독립적인 식으로 다시 구성할 수 있습니다. SQL Server에서는 이러한 독립 식을 서로에 대해 임의의 순서로 계산할 수 있습니다. 결과 열을 계산하기 전에 조인을 비롯한 필터링 작업이 반드시 적용되는 것은 아닙니다.

다음 예에서 SELECT 목록의 식 x/y 는 쿼리 결과로 적합하지 않은 행에 대해서도 언제든지 계산할 수 있습니다.

USE tempdb
GO
IF OBJECT_ID('T','U') IS NOT NULL
    DROP TABLE T
IF OBJECT_ID('S','U') IS NOT NULL
    DROP TABLE S
GO
CREATE TABLE T(x float, y float, z nvarchar(30))
CREATE TABLE S(a float, b float)
GO
INSERT INTO T VALUES (1, 0, 'unknown')
INSERT INTO T VALUES(1, 2, '10')
GO
INSERT INTO S VALUES (1, 1)
INSERT INTO S VALUES (1, 2)
INSERT INTO S VALUES (1, 3)
INSERT INTO S VALUES (1, 4)
INSERT INTO S VALUES (1, 5)

다음 쿼리는 SQL Server 2008에서 실패하지만 SQL Server 2000에서는 완료됩니다.

SELECT x/y FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

y=0에 대해 식을 계산할 때 x/y 식에서 0으로 나누기 오류가 발생하므로 이 쿼리는 실패합니다.

이 쿼리를 올바르게 실행할 수 있는 코드는 다음과 같습니다.

SELECT x/NULLIF(y,0) FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

식 NULLIF(y,0)은 y = 0이면 NULL을 반환합니다. 그렇지 않으면 이 식은 y의 값을 반환합니다. 식 x/NULL은 NULL을 생성하며 예외가 발생하지 않습니다.

문자 데이터를 숫자 유형으로 변환하는 다음 예를 살펴 보십시오.

SELECT CONVERT(tinyint, z) FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

쿼리에서 문자열 'unknown'을 tinyint로 변환하려고 시도하면 변환 오류로 인해 쿼리가 실패합니다. 이 문제를 해결할 수 있는 한 가지 방법은 다음과 같이 CASE 문을 사용하여 z가 numeric인 경우에만 변환하도록 쿼리를 수정하는 것입니다.

SELECT CASE WHEN ISNUMERIC(z) = 1
    THEN CONVERT(tinyint, z) 
    ELSE 0 
END
FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

두 번째 방법은 데이터베이스에서 특수 문자열 값 'unknown'을 사용하지 말고 대신 NULL을 사용하는 것입니다. 세 번째 방법은 z 열의 유형을 tinyint로 변경하여 변환을 사용하지 않는 것입니다. 이러한 해결 방법을 적용하려면 각각 데이터와 스키마를 변경해야 하므로 쿼리를 수정하는 것보다 더 번거로울 수 있습니다. 그러나 이러한 방법을 통해 다른 쿼리를 작성하기가 쉬워지면 이 방법을 고려해 볼 수 있습니다.

집계 함수에서 실행된 NULL 입력 경고

MIN과 같은 집계 함수는 입력에 NULL이 포함된 경우 NULL 값이 제거되었다는 경고를 표시합니다. 이 경고는 계획에 종속될 수 있습니다. 집계에 대해 NULL 입력을 처리하지 않고 경고가 표시되지 않도록 하려면 로컬로 쿼리를 수정하여 NULL 값을 제거합니다. 다음 예에서 SELECT 문을 살펴 보십시오.

USE tempdb
GO
IF OBJECT_ID('newtitles','U') IS NOT NULL
....DROP TABLE newtitles 
GO
CREATE TABLE dbo.newtitles 
   (title varchar (80) NULL ,
    pubdate datetime NULL)
GO
INSERT dbo.newtitles VALUES('Title 1', NULL)
INSERT dbo.newtitles VALUES('Title 2', '20050311')
GO
SELECT t.title, t.pubdate, m.min_pubdate
FROM newtitles AS t,
   (SELECT MIN(pubdate) AS min_pubdate 
    FROM newtitles) AS m
WHERE t.pubdate = m.min_pubdate
GO

SQL Server 2008에서 이 쿼리는 경고를 생성합니다. 경고가 발생하지 않도록 하려면 집계 전에 WHERE pubdate IS NOT NULL 조건을 추가하여 필터링을 통해 NULL 값을 제거하도록 쿼리를 변경합니다.

SELECT t.title, t.pubdate, m.min_pubdate
FROM newtitles AS t,
   (SELECT MIN(pubdate) AS min_pubdate 
    FROM newtitles
    WHERE pubdate IS NOT NULL) AS m
WHERE t.pubdate = m.min_pubdate
GO

참고 항목

관련 자료