2014-02-21 2 views
4

유형 캐스팅 varchar 열에 집계 함수를 수행 할 때 "8114, 수준 16, 상태 5, 줄 1, 메시지 1을받습니다. 데이터 형식을 bigint로 변환하는 중 오류가 발생했습니다." 쿼리 where 절은 숫자가 아닌 값을 필터링해야합니다.MSSQL 집계가 where 절을 무시합니다.

테이블 구조는 유사하다 :

IF EXISTS (SELECT * FROM sys.all_objects ao WHERE ao.name = 'Identifier' AND ao.type = 'U') BEGIN DROP TABLE Identifier END 
IF EXISTS (SELECT * FROM sys.all_objects ao WHERE ao.name = 'IdentifierType' AND ao.type = 'U') BEGIN DROP TABLE IdentifierType END 

CREATE TABLE IdentifierType 
(
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [Style] [int] NULL, 
    CONSTRAINT [PK_IdentifierType_ID] PRIMARY KEY CLUSTERED ([ID] ASC) 
) ON [PRIMARY] 

CREATE TABLE Identifier 
(
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [IdentifierTypeID] [int] NOT NULL, 
    [Value] [nvarchar](4000) NOT NULL, 
    CONSTRAINT [PK_Identifier_ID] PRIMARY KEY CLUSTERED ([ID] ASC) 
) ON [PRIMARY] 

ALTER TABLE Identifier WITH CHECK ADD CONSTRAINT [FK_Identifier_IdentifierTypeID] FOREIGN KEY([IdentifierTypeID]) REFERENCES IdentifierType ([ID]) 
GO 

Identifier.Value는 VARCHAR 컬럼, 그것은 수 있고 숫자가 아닌 데이터를 포함한다. IdentifierType.Style = 0으로 쿼리를 필터링하면 'Value'가 정수의 문자열 표현 만 반환한다는 것을 의미합니다. 아래 쿼리는 "메시지 8114, 수준 16, 상태 5, 줄 1과 함께 실패합니다. 데이터 형식을 nvarchar에서 bigint로 변환하는 중 오류가 발생했습니다."

SELECT 
    MAX(CAST(Value AS BIGINT)) 
FROM 
    Identifier i, 
    IdentifierType it 
WHERE 
    i.IdentifierTypeID = it.ID AND 
    it.Style = 0 

WHERE 절을 확장하여 'AND ISNUMERIC (i.Value) = 1'을 포함하면 최대 정수 값을 반환합니다. 그건 내 결과 집합에 숫자가 아닌 문자열이 있음을 의미합니다. 그럼에도 불구하고이 행은 반환되지 않습니다.

SELECT 
    * 
FROM 
    Identifier i, 
    IdentifierType it 
WHERE 
    i.IdentifierTypeID = it.ID AND 
    it.Style = 0 AND 
    ISNUMERIC(i.Value) <> 1 

유형 캐스팅을 트리핑하는 행을 식별 할 수 없었습니다. 위의 쿼리는 예외 행을 노출해야합니다. 또한 빈 문자열이나 극히 긴 문자열도 없습니다 (가장 큰 문자열은 6 자입니다)

MSSQL이 WHERE 절을 먼저 필터링하지 않고 모든 행에서 CAST를 수행하려고 할 가능성이 있습니까?

다른 사람이 본 것이 있습니까?

쿼리의 구성 요소를 임시 테이블에 인스턴스화하고 그 중 최대 값을 선택하는 두 번째 방법이 있습니다.

SELECT 
    Value 
INTO 
    IdentifierClone 
FROM 
    Identifier i, 
    IdentifierType it 
WHERE 
    i.IdentifierTypeID = it.ID AND 
    it.Style = 0 

SELECT MAX(CAST(Value as BIGINT)) FROM IdentifierClone 

하위 쿼리가 작동하지 않습니다.

모든 도움이나 생각을 해주십시오.

+3

참조 [비논리적 인 오류를 발생하지 않아야 SQL 서버] https://connect.microsoft.com/SQLServer/feedback/details/537419/ SQL 서버 - 비 - 제기 - 비논리적 - 오류) Connect 피드백 사이트에서. SQL Server는 때로는 앞을 뛰어 넘고 이전의 변환을 수행하여 실제로 논리적 인 순서로 쿼리를 처리하는 경우 생성되지 않는 오류를 발생시킵니다. –

+0

숫자 값을 찾지 않고 isnumeric 자체로 인해 예상되는 결과를 얻지 않으려 고 시도하면서 isnumeric과 비슷한 문제가있었습니다. 질서의 문제라면 서브 테이블로 구성하여 더 나은지 확인하십시오. 서브 테이블에서 where 절을 수행 한 다음 캐스트를 수행하십시오. 그렇게하기 전에 필터링 된 것 같습니다. –

+2

@MatheseF - 하위 쿼리를 언급하는 경우 "이전에 필터링되었는지"가 잘못되었습니다. 최적화 프로그램은 하위 쿼리를 사용하여 변환 및 필터링을 다시 정렬 할 수 있으며 여전히 이러한 비논리적 오류를 생성 할 수 있습니다. 내가 그것을 방지하기 위해 알고있는 유일한 확실한 방법은 두 개의 완전히 별개의 쿼리로 쿼리를 분할하고 두 번째 쿼리가 작동하는 임시 테이블/테이블 변수를 첫 번째 쿼리에 채우게하는 것입니다. –

답변

0

REGEX 표현식을 사용하여 문제 레코드를 찾으십시오. 여기 ISNUMERIC 문제 그러나 정규식 표현을 감지하지 않는 예입니다 않습니다

CREATE TABLE tst (value nvarchar(4000)) 
INSERT INTO tst select '£' 
-- Record found ... 
SELECT * FROM tst WHERE value NOT LIKE '%[0-9]%' 
-- No record found ... 
SELECT * from tst where isnumeric(value) <> 1 
(
+0

문자열이 정수로 변환 될 수 있는지 테스트하는 방법을 제안하려는 경우, 첫 번째 SELECT의 조건은 'LIKE'[% -9] % ''(* 변환 할 수없는 값을 찾으려면). –