我写了一个CTE来从数据集中删除非数值,然后计算一个范围内的数值。
WITH dtr
AS ( SELECT resultlevel r
FROM dbo.Result
WHERE DrugID = 'AMP'
AND ISNUMERIC(ResultLevel) = 1
AND AuditStamp > '1/1/2016'
AND DeleteFlag = 0
)
SELECT COUNT(*)
FROM dtr
WHERE CONVERT(INT, r) BETWEEN 50 AND 75
这会在SMS中返回错误
Msg 245, Level 16, State 1, Line 2
Conversion failed when converting the varchar value 'PND ' to data type int.
如果没有' dtr'这个错误是完全可能的。在CTE中查询。
当我重写这个时,而不是CTR,而是一个TEMP表,它可以工作。
SELECT resultlevel r
INTO #d
FROM dbo.Result
WHERE DrugID = 'AMP'
AND ISNUMERIC(ResultLevel) = 1
AND AuditStamp > '1/1/2016'
AND DeleteFlag = 0
SELECT COUNT(*)
FROM #d
WHERE CONVERT(INT, r) BETWEEN 50 AND 75
所以我的问题是为什么?我一直认为CTE就像创建TEMP表一样。
测试数据
if object_id('tempdb..#temp') is not null drop table #temp
create table #temp (result char(5))
insert into #temp (result) values
('1'),('A'),('>2'),('PEN ') ,('@3'),('-2'),('-33')
;with isnum AS (
SELECT result
FROM #temp
WHERE ISNUMERIC(result) = 1)
--Selecting from the CTE yields 1, -2, and -33 all of which can be converted to INT
--Running the query with the where clause causes the conversion error
SELECT
result,
ISNUMERIC(result)
FROM isnum
--WHERE CONVERT(INT,result) > 1
答案 0 :(得分:3)
在SQL Server
中有Logical Processing Order of the SELECT statement,它确定在后续步骤中一个步骤中定义的对象何时可用于子句:
这是您的查询将被处理的方式,并且您的查询看起来非常好。但有时,SQL Server
决定不遵循此顺序以优化您的查询。
在您的情况下,在应用SQL Server
过滤之前,convert
可能只是简单地将您的查询转换为另一个并执行where isnumeric
函数。
如果我们使您的查询更复杂(但仍然给出相同的结果),SQL Server
这次正确执行代码:
;with isnum AS (
SELECT result
FROM #temp
WHERE ISNUMERIC(result) = 1
GROUP BY result
HAVING MAX(result) = result
)
SELECT
result,
ISNUMERIC(result)
FROM isnum
WHERE CONVERT(INT,result) > 1;
在你的情况下(这就是我在这种情况下所做的事情,当不同类型存储在一列中时),你可以简单地使用TRY_CONVERT函数:
;with isnum AS (
SELECT result
FROM #temp
WHERE ISNUMERIC(result) = 1)
SELECT
result,
ISNUMERIC(result)
FROM isnum
WHERE TRY_CONVERT(INT, result) > 1