我有SQL Server 2008 R2,Windows 7操作系统。
在服务器中,我有一个表con1
,它是通过以下SQL语句创建的。
CREATE TABLE [dbo].[con1](
[digit_str] [nvarchar](50) NULL
) ON [PRIMARY]
在con1
表中,我有以下值:
digit_str
----------------
1
1
2
3
4
5
1.
我确实对数据库执行了以下SQL语句:
SELECT t1.digit FROM
(
select CAST(digit_str as int) as digit from con1 where RIGHT(digit_str,1) <> '.'
) as t1
where t1.digit <> 1
服务器给我以下错误消息:
转换nvarchar值'1'时转换失败数据类型为int。
我认为我的内部SQL首先执行并创建了临时表t1
,因此表1.
中不包含t1
,然后SQL解析器将使用where t1.digit <> 1
来过滤临时表t1
。
但上面似乎不对,所以任何人都解释了上述SQL的执行顺序吗?
答案 0 :(得分:4)
这是SQL Server的一个已知“功能”。不要假设WHERE子句在SELECT子句之前执行。
请参阅:SQL Server should not raise illogical errors
有时这样做有充分的理由。考虑加入两个表,A比B小得多。
select CAST(A.col1 as int), A.col2, B.col3
from A join B ...
where ... isnumeric(A.col1) = 1
如果您正确或错误地检查生成的查询计划,SQL服务器将从A流式传输数据作为要加入B的前导行。这样做时,它知道它只需要拉col2
和function on col1
。它可以使col1
只是为了稍后运行该函数,或者对于像CAST一样微不足道的东西,SQL Server也可以在流式传输过程中转换数据。
有一件事是肯定的,这种策略确实使SQL Server在某些查询中更快一点。但从纯粹的逻辑角度来看,我称之为一个错误。
答案 1 :(得分:0)
我无法解释这种行为,但以下内容可以帮助您:
SELECT t1.digit FROM
(
select CAST(digit_str as int) as digit
from con1
where RIGHT(digit_str,1) <> '.'
AND digit_str <> '1'
) as t1
我不确定为什么最后的 where 子句会导致执行转换,因为它看起来应该已经从t1的结果集中过滤掉了。