为什么此查询在存储过程中返回不同的结果?

概要 我有一个带有
WHERE
子句的查询,该子句包含一个条件,该条件针对可能为NULL的参数检查NULLable列,如下所示:
SELECT ...
FROM Table
WHERE NullableColumn = @NullableParameter
根据我的理解,SQL Server应该总是将
NULL = NULL
non-NULL = NULL
评估为false,这意味着如果
@NullableParameter
为NULL,则上述查询将返回零记录。 这是我在查询窗口中运行查询时看到的行为,但是当我在存储过程中使用相同的查询时,当
@NullableParameter
为NULL时,它返回所有记录,其中
NullableColumn
为NULL。简而言之,似乎sproc正在说
NULL = NULL
是真的。 这就是问题/问题。实际的
WHERE
条款涉及更多,并在下面的部分中提供了更多细节。 坚韧不拔的细节 我有一个名为StudyResults的数据库。每条记录由
StudyResultId
主键字段唯一标识。还有一个
ParticipantId
字段,表示参与研究的主题,和
GroupId
,它标识主题属于哪个组,如果有的话。如果该研究是单人研究,则
GroupId
为NULL。
ParticipantId
不能为NULL。 我有一个存储过程,需要更新StudyResults表中某些特定研究的记录,但这里有一点 - 如果研究是单人研究,那么我需要更新那一行;如果是小组研究,我想更新该组的StudyResults中的所有行。 这不是很难完成。传递存储过程
StudyResultId
,然后运行以下T-SQL以确定该行的
GroupId
ParticipantId
值:
DECLARE @GroupId INT, @ParticipantId INT
SELECT @GroupId = GroupId,
       @ParticipantId = ParticipantId
FROM StudyResults
WHERE StudyResult = @StudyResultId
接下来,我创建一个CURSOR来枚举感兴趣的StudyResults记录。注意
WHERE
条款,其中说:“给我记录,其中
StudyResultId
等于
@StudyResultId
进入sproc或
GroupId
ParticipantId
值与
GroupId
ParticipantId
值对应的StudyResults记录。
DECLARE resultsToEnumerate CURSOR LOCAL FAST_FORWARD FOR 
SELECT DISTINCT StudyResultId
FROM StudyResults
WHERE StudyResult = @StudyResultId OR (GroupId = @GroupId AND ParticipantId= @ParticipantId)
如果
@GroupId
为NULL,那么比较
GroupId = @GroupId
应该总是假的,对吧?因为对于SQL Server,
NULL = NULL
为false,而
non-NULL = NULL
为false。 但是这里有些奇怪 - 如果我从查询窗口运行上述语句并使用
@StudyResultId
进行单人研究,则CURSOR包含我所期望的 - 即单个记录。但是,如果我将完全相同的代码放在存储过程中并运行它,则CURSOR包含该参与者的所有单人研究!就好像它说
@GroupId
是NULL,所以我会返回所有记录,其中
GroupId
是NULL,但为什么呢?
NULL = NULL
永远不应该返回记录,对吧? 事实上,如果我进入sproc并更改
WHERE
条款并将
GroupID = @GroupID
替换为
NULL = NULL
,我会看到相同的结果 - 所有参与者的单人研究。所以它显然是在sproc中评估
NULL = NULL
为真(或忽略它)。 解决方法 我可以通过在括号中添加一个额外的检查来“修复”这个存储过程,以确保
GroupId IS NOT NULL
像这样:
WHERE ActivityID = @ActivityID OR (GroupID IS NOT NULL AND GroupID = @GroupID AND PatientID = @PatientID)
这就是我所做的,但我很困惑为什么在我的存储过程中对
WHERE
子句进行不同的评估。     
已邀请:
将ANSI_NULLS设置为ON后,尝试更改会话中的存储过程。
SET ANSI_NULLS ON
GO

alter procedure procedureName 
...
来自文档:   对于存储过程,SQL Server使用   来自的SET ANSI_NULLS设置值   最初的创作时间   存储过程。每当存储   程序随后执行,   SET ANSI_NULLS的设置是   恢复到原来使用的值   并生效。在里面调用时   存储过程,SET的设置   ANSI_NULLS未更改。     
添加这行代码
>   WITH RECOMPILE
在程序开始时,它确保构建一个新的执行计划,而不是依赖于先前的执行。     

要回复问题请先登录注册