gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 22:22:53 26 4
gpt4 key购买 nike

概要

我有一个带有 WHERE 子句的查询,该子句包含一个条件,该条件根据可能为 NULL 的参数检查可空列,如下所示:

SELECT ...
FROM Table
WHERE NullableColumn = @NullableParameter

根据我的理解,SQL Server 应该将 NULL = NULL non-NULL = NULL 始终评估为 false,这意味着如果 @NullableParameter为 NULL 那么上面的查询将返回零条记录。

这是我在查询窗口中运行查询时看到的行为,但是当我在存储过程中使用相同的查询并且@NullableParameter为NULL时,它会返回的所有记录NullableColumn 为 NULL。简而言之,存储过程似乎在说 NULL = NULL 是正确的。

这就是问题/问题简而言之。实际的 WHERE 子句涉及更多一些,并在下面的部分中提供更多详细信息。

坚韧的细节

我有一个数据库,其中有一个名为 StudyResults 的表。每条记录均由 StudyResultId 主键字段唯一标识。还有一个 ParticipantId 字段,用于指示参与研究的受试者;以及 GroupId,用于标识受试者所属的组(如果有)。如果研究是单人研究,则 GroupId 为 NULL。 ParticipantId 不能为 NULL。

我有一个存储过程,需要更新特定研究的 StudyResults 表中的一些记录,但问题是 - 如果该研究是单人研究,那么我只需要更新它一排;如果这是一项小组研究,我想更新该小组、该主题的 StudyResults 中的所有行。

这并不难实现。存储过程将传递一个 StudyResultId,然后运行以下 T-SQL 来确定该行的 GroupIdParticipantId 值:

DECLARE @GroupId INT, @ParticipantId INT
SELECT @GroupId = GroupId,
@ParticipantId = ParticipantId
FROM StudyResults
WHERE StudyResult = @StudyResultId

接下来,我创建一个 CURSOR 来枚举感兴趣的 StudyResults 记录。请注意 WHERE 子句,它表示:“给我记录,其中 StudyResultId 等于传递到存储过程的 @StudyResultId GroupIdParticipantId 值与 StudyResults< 的 GroupIdParticipantId 值一致/strong> 兴趣记录。

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 包含我所期望的内容 - 即一条记录。但是,如果我将完全相同的代码放入存储过程中并运行它,光标将包含该参与者的所有单人研究!就好像说 @GroupId 为 NULL,所以我将返回 GroupId 为 NULL 的所有记录,但为什么呢? NULL = NULL 永远不应该返回记录,对吗?

事实上,如果我进入存储过程并更改 WHERE 子句并将 GroupID = @GroupID 替换为 NULL = NULL 我明白了相同的结果 - 所有针对相关参与者的单人研究。因此,它显然正在存储过程中将 NULL = NULL 评估为 true(或忽略它)。

解决方法

我可以通过在括号中添加额外的检查来“修复”存储过程中的此问题,以确保 GroupId IS NOT NULL 如下所示:

WHERE ActivityID = @ActivityID OR (GroupID IS NOT NULL AND GroupID = @GroupID AND PatientID = @PatientID)

这就是我所做的,但我很困惑为什么在我的存储过程中对 WHERE 子句的评估不同。

最佳答案

将 ANSI_NULLS 设置为 ON 后,尝试更改 session 中的存储过程。

SET ANSI_NULLS ON
GO

alter procedure procedureName
...

来自the docs :

For stored procedures, SQL Server uses the SET ANSI_NULLS setting value from the initial creation time of the stored procedure. Whenever the stored procedure is subsequently executed, the setting of SET ANSI_NULLS is restored to its originally used value and takes effect. When invoked inside a stored procedure, the setting of SET ANSI_NULLS is not changed.

关于sql-server - 为什么此查询在存储过程中返回不同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4502416/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com