最近在工作中常常遇到数据库 SP 执行完成后总是返回同一个结果的问题,分析后问题出在 SP 中声明变量后未为其赋初值, SP 执行过程中也没有进入到为其赋值的子句,则变量一直保持默认值 NULL
,导致最终无法满足任何判断条件而总是执行不正确的结果。
首先,我在数据库里新建了一张名为
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相关条目里有更详尽的分析和说明,各位可以参考。
当然,问题不能一概而论,在此我也只是提出一种问题原因和修补的方法,各位还是要根据自己面临的业务需求灵活选择。程序的设计和编写就是一个 制造错误 发现错误 修改错误 带入新错误
的螺旋上升过程,同时也是广大程序员们为其着迷,疯狂,咒骂,悲伤却依旧乐此不疲的原因。