我有一个奇怪的问题,当在类型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
但子查询不起作用。
任何帮助或想法,将不胜感激。
参见[SQL Server应不会提高不合逻辑的错误(https://connect.microsoft.com/SQLServer/feedback/details/537419/ sql-server-should-not-raise-illogical-errors)。 SQL Server有时会跳转到前面并执行较早的转换,如果它实际上以正确的逻辑顺序处理查询,则会产生不会产生的错误。 –
我有一些与isnumeric类似的问题,试图找到没有数字值,并没有得到我期望的结果由于isnumeric本身。如果这是一个命令问题,请尝试使用子表进行组织,以查看它是否更好,请在子表中执行where子句,然后执行演员操作。你确定它是这样过滤的。 –
@MatheseF - 如果您指的是一个子查询,那么您在“确保它在之前被过滤”是错误的 - 优化程序可以和*将重新排列转换和过滤,即使使用子查询也可以产生这些不合逻辑的错误。我知道阻止它的唯一可靠方法是将查询拆分为两个完全独立的查询,并让第一个查询填充第二个查询随后执行的临时表/表变量。 –