【搬家】【数据库】【语法】SQL 中声明变量使用默认初值存在的隐患

本文最早于 2013年12月21日于本人个人博客(http://mooowooo.tk)发表,现博客搬家至此,转载请注明出处。


最近在工作中常常遇到数据库 SP 执行完成后总是返回同一个结果的问题,分析后问题出在 SP 中声明变量后未为其赋初值, SP 执行过程中也没有进入到为其赋值的子句,则变量一直保持默认值 NULL,导致最终无法满足任何判断条件而总是执行不正确的结果。

Talk is week, let me show you my code.

首先,我在数据库里新建了一张名为 EMPLOYEE 的表,并向其中塞入了一笔数据,如下图

然后,新建一个查询,输入如下 SQL 代码,注意 IF 语句中条件的设置。

DECLARE @Result VARCHAR(20) 
SELECT @Result 
IF EXISTS ( SELECT 1 FROM EMPLOYEE WHERE NAME='MOOOWOOO' AND ID='000')
BEGIN 
    SET @Result = 'Y'
END

IF @Result = 'Y'
BEGIN 
   SELECT 'It is Ok !'
END 
ELSE
BEGIN 
   SELECT 'It is Wrong !'
END
执行的结果如下图所示:

很显然,因为 EMPLOYEE 表中不存在满足这样条件一笔数据,所以 @Result = 'Y' 一定不成立,自然的,执行结果会进入 ELSE 子句。现在我们来做一点修改:

DECLARE @Result VARCHAR(20) 
SELECT @Result 
IF EXISTS ( SELECT 1 FROM EMPLOYEE WHERE NAME='MOOOWOOO' AND ID='000')
BEGIN 
    SET @Result = 'Y'
END

IF @Result <> 'Y'    -- 该处条件已经改变
BEGIN 
   SELECT 'It is Ok !'
END 
ELSE
BEGIN 
   SELECT 'It is Wrong !'
END
执行结果如下图所示:

出现了奇怪的现象,按道理来说,我们修改了条件,@Result <> 'Y' 是一定成立的,理应满足 IF 的判断条件,但为何还是执行进入了 ELSE 子句呢?此时我们根据图片的来分析,在声明 @Result 变量时,我特意留空不为其赋初值,并将其默认值 SELECT 出来。大家已经发现,SQL Server 未没有显式赋初值的变量默认赋值为 NULL

于是我们推测,问题出在 NULL 上。稍安勿躁,我们将代码进一步修改成下面的情况来验证我们的猜想。

DECLARE @Result VARCHAR(20) 
SELECT @Result 
IF EXISTS ( SELECT 1 FROM EMPLOYEE WHERE NAME='MOOOWOOO' AND ID='000')
BEGIN 
    SET @Result = 'Y'
END

IF @Result = 'Y'
BEGIN 
   SELECT 'It is Ok !'
END 
ELSE @Result <> 'Y'
BEGIN 
   SELECT 'It is Wrong !'
END
ELSE @Result IS NULL
BEGIN
    SELECT 'It is NULL !'
END
ELSE
BEGIN
    SELECT 'What the HELL ???'
END
执行结果如下图:

看来问题就出在 NULL 这个特殊的值上。NULL 是一个极为特殊的值,不存在任何实际的值能与之建立逻辑关系,包括 NULL 自身。有兴趣又对此问题不太清楚的朋友可以对上面的语句增加如下的一个 ELSE 子句进行验证:

ELSE IF @Result = NULL
BEGIN
    SELECT 'It is =NULL !'
END

结果应该很清楚。所以我们知道了,在判断时,对于值为 NULL 的变量来说,只能使用系统提供的 IS 操作符来判断。为了防止出现与我一样的悲剧,建议在编写 SQL 代码时在声明变量的同时就为其显示赋初值,或者对于值可能为 NULL 的情况增加分支判断。对于这个问题,Wikipedia相关条目里有更详尽的分析和说明,各位可以参考。

当然,问题不能一概而论,在此我也只是提出一种问题原因和修补的方法,各位还是要根据自己面临的业务需求灵活选择。程序的设计和编写就是一个 制造错误 发现错误 修改错误 带入新错误 的螺旋上升过程,同时也是广大程序员们为其着迷,疯狂,咒骂,悲伤却依旧乐此不疲的原因。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值