2

这是在 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
4

3 回答 3

4

PhoneNumber1和的数据类型是PhoneNumber2什么?的定义是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 条件下返回变量。

于 2012-04-18T18:05:22.330 回答
3

您的dbo.fPhoneExists函数在表达式中包含隐式转换PhoneNumber = 0,根据数据类型 Peecendence的规则将PhoneNumberVARCHAR 值转换为 int。如果字符串中的值不是数字,则此转换将失败。您还陷入了假设在 SQL 中保证布尔运算符短路的谬误,这根本不是真的。SQL 是一种声明性语言,不保证布尔运算符的求值顺序

于 2012-04-18T18:37:56.747 回答
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())))
      )

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

于 2012-04-18T19:13:14.453 回答