T-SQL存储过程NULL输入值导致select语句失败

时间:2008-12-19 12:53:27

标签: sql tsql stored-procedures parameters null

下面是一个存储过程,用于根据单独检查所有字段来检查数据库中是否存在重复条目(不要问我为什么要这样做,只需要这样)。

听起来非常简单,但SP失败了。 问题是传递给SP的一些参数可能具有空值,因此sql应该读为“is null”而不是“= null”。 我已尝试使用exec()和sp_executesql的isnull(),case语句,coalesce()和动态sql,但未能实现其中任何一个。这是代码......

CREATE PROCEDURE sp_myDuplicateCheck
 @userId int,
 @noteType char(1),
 @aCode char(3),
 @bCode char(3), 
 @cCode char(3),
 @outDuplicateFound int OUT
AS
BEGIN
SET @outDuplicateFound = (SELECT Top 1 id FROM codeTable 
                          WHERE userId = @userId
                          AND noteType = @noteType
                          AND aCode = @aCode
                          AND bCode = @bCode
                          AND cCode = @cCode 
                          )
-- Now set the duplicate output flag to a 1 or a 0
IF (@outDuplicateFound IS NULL) OR (@outDuplicateFound = '') OR (@outDuplicateFound = 0)
 SET @outDuplicateFound = 0
ELSE 
 SET @outDuplicateFound = 1
END

6 个答案:

答案 0 :(得分:10)

对于每个可能为null的参数,我认为你需要这样的东西:

AND (aCode = @aCode OR (aCode IS NULL AND @aCode IS NULL))

答案 1 :(得分:7)

如果我理解你的问题,那么我鼓励你做一些研究:

SET ANSI_NULLS OFF

如果在存储过程中使用此命令,则可以在比较中使用= NULL。请查看以下示例代码,了解其工作原理。

Declare @Temp Table(Data Int)

Insert Into @Temp Values(1)
Insert Into @Temp Values(NULL)

-- No rows from the following query
select * From @Temp Where Data = NULL

SET ANSI_NULLS OFF

-- This returns the rows where data is null
select * From @Temp Where Data = NULL

SET ANSI_NULLS ON

每当您将ANSI_NULLS设置为Off时,最好尽快将其设置为ON,因为这可能会影响您稍后运行的其他查询。所有SET命令仅影响当前会话,但根据您的应用程序,这可能会跨越多个查询,这就是为什么我建议您在此查询后立即重新启用ansi null。

答案 2 :(得分:1)

我认为这应该适用于COALESCE功能。试试这个:

CREATE PROCEDURE sp_myDuplicateCheck
 @userId int,
 @noteType char(1),
 @aCode char(3),
 @bCode char(3), 
 @cCode char(3),
 @outDuplicateFound int OUT
AS
BEGIN

SET @outDuplicateFound = (SELECT Top 1 id FROM codeTable 
                          WHERE userId = @userId
                          AND noteType = @noteType
                          AND COALESCE(aCode,'NUL') = COALESCE(@aCode,'NUL')
                          AND COALESCE(bCode,'NUL') = COALESCE(@bCode,'NUL')
                          AND COALESCE(cCode,'NUL') = COALESCE(@cCode,'NUL')
                          )
-- Now set the duplicate output flag to a 1 or a 0
IF (@outDuplicateFound IS NULL) OR (@outDuplicateFound = '') OR (@outDuplicateFound = 0)
 SET @outDuplicateFound = 0
ELSE 
 SET @outDuplicateFound = 1
END

祝你好运!

杰森

答案 3 :(得分:0)

我首先添加一个检查以查看所有参数在运行时是否为空,即

IF(COALESCE(@userId, @noteType, @aCode, @bCode, @cCode) IS NULL)
   BEGIN
       -- do something here, log, print, return, etc.
   END

然后,在您验证用户传入的内容后,您可以在WHERE子句中使用类似的内容

WHERE userId = COALESCE(@userId, userId)
AND noteType = COALESCE(@noteType, noteType)
AND aCode    = COALESCE(@aCode, aCode)
AND bCode    = COALESCE(@bCode, bCode)
AND cCode    = COALESCE(@cCode, cCode)

编辑:我可能错过了如果参数作为null传入的意图,这意味着您明确要将列测试为null。我上面的where子句假设null参数意味着'跳过此列上的测试。'

或者,我相信您可以使用原始查询并在存储过程创建时添加ANSI_NULLS set选项。例如,

SET ANSI_NULLS OFF
GO
CREATE PROC sp_myDuplicateCheck....

实际上,这应该允许您的代码然后评估column = null而不是column为null。我认为Kalen Delaney曾经将ANSI _NULLS和QUOTED_IDENTIFIER 选项创造为“粘性选项”,因为如果它们设置在过程创建时间,那么它们会在运行时保留该过程,无论其连接方式如何时间已经确定。

答案 4 :(得分:0)

试试这个:

CREATE PROCEDURE sp_myDuplicateCheck
     @userId int = 0,
     @noteType char(1) = "",
     @aCode char(3) = "", 
     @bCode char(3) = "", 
     @cCode char(3) = "",
     @outDuplicateFound int OUT
    AS
    BEGIN
    SET @outDuplicateFound = (SELECT Top 1 id FROM codeTable 
                              WHERE @userId in (userId ,0)
                              AND @noteType in (noteType,"")
                              AND @aCode in (aCode , "")
                              AND @bCode in (bCode , "")
                              AND @cCode in (cCode ,"")
                              )
    -- Now set the duplicate output flag to a 1 or a 0
    IF (@outDuplicateFound IS NULL) OR (@outDuplicateFound = '') OR (@outDuplicateFound = 0)
     SET @outDuplicateFound = 0
    ELSE 
     SET @outDuplicateFound = 1
    END

这基本上做的是在null为空的情况下为输入参数提供默认值,然后在where条件中仅在 时为值提供默认值。

答案 5 :(得分:0)

SET ANSI_NULLS OFF/On

这样你就可以colName = null