2014-02-21 42 views
4

我有一个奇怪的问题,当在类型cast varchar列上执行聚合函数时,我收到“Msg 8114,Level 16,State 5,Line 1.将数据类型nvarchar转换为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”仅返回整数的字符串表示形式。下面的查询失败,出现“Msg 8114,Level 16,State 5,Line 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是否有可能试图对所有行执行CAST,而不是先通过WHERE子句进行筛选?

还有其他人看过类似的东西吗?

还有第二个工作是将查询的组件实例化到临时表中,然后从中选择MAX值。

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 Server应不会提高不合逻辑的错误(https://connect.microsoft.com/SQLServer/feedback/details/537419/ sql-server-should-not-raise-illogical-errors)。 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'%[^ 0 -9]%''(找到*不*可转换的值)。 –