将varchar值'N'转换为数据类型int时转换失败

时间:2012-04-18 17:59:11

标签: sql-server sql-server-2008

这是在SQL Server 2008 R2中。

我正用这个拉我的头发。请密切关注。

当我运行它时,我返回了27行:

select * 
from dbo.[12STD_NO_VISIT] 
where (
         (dbo.fPhoneExists(PhoneNumber1) = 1  
         AND (NextCall1 BETWEEN GETDATE() AND DATEADD(hh, 1, GETDATE())))
      )

当我运行这个时,我得到21行返回(注意对PhoneNumber2和NextCall2的更改):

select * 
from dbo.[12STD_NO_VISIT] 
where (
          (dbo.fPhoneExists(PhoneNumber2) = 1  
           AND (NextCall2 BETWEEN GETDATE() AND DATEADD(hh, 1, GETDATE())))
      )

但是,当我运行这个时,'ORing'这两个条件,我得到一个错误:

  

将varchar值'N'转换为数据类型int

时转换失败
select * 
from dbo.[12STD_NO_VISIT] 
where (
          (dbo.fPhoneExists(PhoneNumber1) = 1  
           AND (NextCall1 BETWEEN GETDATE() AND DATEADD(hh, 1, GETDATE())))
       OR  
          (dbo.fPhoneExists(PhoneNumber2) = 1
           AND (NextCall2 BETWEEN GETDATE() AND  DATEADD(hh, 1, GETDATE())))
      )

但它不只是给我错误。它首先检索42行,显示一行(结果选项卡),然后显示错误(消息选项卡)。

我无法想出这个。非常感谢任何帮助。

谢谢!

FUNCTION [dbo].[fPhoneExists](@PhoneNumber varchar) 
RETURNS BIT 
WITH EXECUTE AS CALLER 
AS 
BEGIN 
DECLARE @GoodNumber bit 
IF (@PhoneNumber is NULL or @PhoneNumber = 0 or @PhoneNumber = '') 
  SET @GoodNumber = 0; 
ELSE 
  SET @GoodNumber = 1; 
  Return(@GoodNumber); 
END

3 个答案:

答案 0 :(得分:4)

PhoneNumber1PhoneNumber2有哪些数据类型? dbo.fPhoneExists的定义是什么?我怀疑这个问题存在于某个地方 - 或者正如Lynn所暗示的那样,查询可能比你向我们展示的更多(查询会成功或失败作为一个整体;它不会产生42行然后是错误)。

现在我们看到了这个函数,这里是重写:

ALTER FUNCTION [dbo].[fPhoneExists]
(
  @PhoneNumber VARCHAR -- varchar(what)? This should match definition of column
) 
RETURNS BIT 
WITH EXECUTE AS CALLER 
AS 
BEGIN
  RETURN (SELECT CASE WHEN COALESCE(@PhoneNumber, '') IN ('0', '') THEN 0 ELSE 1 END);
END
GO

没有理由将临时逻辑存储在变量中,还要注意您在ELSE条件下返回变量。

答案 1 :(得分:3)

您的dbo.fPhoneExists函数在PhoneNumber = 0表达式中包含一个隐式转换,根据Data Type Peecendence的规则将PhoneNumber VARCHAR值转换为int。如果字符串中的值不是数字,则此强制转换将失败。你也陷入了假设在SQL中保证布尔运算符短路的谬论,这根本不是真的。 SQL是一种声明性语言和order of evaluation of boolean operators is not guaranteed

答案 2 :(得分:1)

通过将fnPhoneExists替换为CASE来替换select * from dbo.[12STD_NO_VISIT] where ( (case when ISNULL(PhoneNumber1,'') not in ('0','') then 1 else 0 end=1 AND (NextCall1 BETWEEN GETDATE() AND DATEADD(hh, 1, GETDATE()))) OR (case when ISNULL(PhoneNumber2,'') not in ('0','') then 1 else 0 end=1 AND (NextCall2 BETWEEN GETDATE() AND DATEADD(hh, 1, GETDATE()))) ) ,您将获得更好的效果:

{{1}}

这是因为优化器不会优化fnPhoneExists的内容。