6

我正在尝试创建一个允许省略参数的存储过程,但如果提供了参数,则进行 ANDed:

CREATE PROCEDURE 
    MyProcedure

    @LastName Varchar(30) = NULL,
    @FirstName Varchar(30) = NULL,
    @SSN INT = NULL
AS

SELECT LastName, FirstName, RIGHT(SSN,4) as SSN
FROM Employees
WHERE 
    (
        (LastName like '%' + ISNULL(@LastName, '') + '%')
            AND 
        (FirstName like '%' + ISNULL(@FirstName, '') + '%')
    )
AND
    (SSN = @SSN)

如果提供了@SSN,我只想执行 AND。还是有其他方法可以做到这一点?

如果提供了 SSN,则查询的 LastName/FirstName 部分将返回所有记录。如果只提供了姓/名,则 AND 会使其不会返回任何记录,因为 SSN 不会验证。

想法?


附加说明

假设一个基本记录集:

First          Last          SSN  
Mike           Smith         123456789  
Tom            Jones         987654321

如果我们改变上面的过程,使它不包括这个块:

AND
    (SSN = @SSN)

然后一切正常,只要我们传递了名字或姓氏。但如果提供了 SSN,我希望能够包含 SSN。

如果我将 AND 更改为 OR,那么我会得到一个错误的结果集,因为查询的 FirstName/LastName 部分计算为:

WHERE (LastName like '%%' and FirstName like '%%')

(当然,这将返回所有记录)


如果我不能有条件地中止 AND,我希望得到类似的东西:

AND
    (SSN like ISNULL(@SSN, '%'))

:-)

4

5 回答 5

16

改变:

AND (SSN = @SSN) 

到:

AND (SSN = @SSN or @SSN is null)

如果SSN从不为空,您还可以执行以下操作:

AND SSN = ISNULL(@SSN, SSN)
于 2012-10-11T17:29:56.260 回答
0

你也可以试试:

(ISNULL(SSN, @SSN) = @SSN)
于 2012-10-11T17:32:08.213 回答
0

您可以将这两个版本的语句放在一个 if 块中。

 AS
 IF @SSN IS NULL
      /*regular statement*/
 ELSE
      /*Statement with @SSN*/

或者

 AND
      SSN = ISNULL(@SSN, SSN)

我从未使用过第二个选项,但我知道它存在。

于 2012-10-11T17:32:34.817 回答
0

这是关于 SQL Server 中动态搜索参数的圣经。你应该这样写

SELECT LastName, FirstName, RIGHT(SSN,4) as SSN
FROM Employees
WHERE (NULLIF(@LastName,'') IS NULL OR LastName LIKE '%' + @LastName + '%')
  AND (NULLIF(@FirstName,'') IS NULL OR FirstName LIKE '%' + @FirstName + '%')
  AND (@SSN is null or SSN = @SSN)
   -- or if not provided means blank, then
   -- (@SSN = '' or SSN = @SSN)
OPTION (RECOMPILE)

顺便说一句,SQL Server 中没有短路布尔值这样的东西。是的,它确实在第一个结论处停止,但不能保证左边的条件在右边之前处理。例如,此代码不安全。我正在使用“ABC.123”,但这也可以是一列。

WHERE ISNUMERIC('ABC.123') = 1 OR CAST('ABC.123' AS INT) > 10

为了说明该AND (@SSN is null or SSN = @SSN)子句,当没有提供@SSN 时,即NULL

   AND (@SSN is null or SSN = NULL)
=> AND (NULL IS NULL or SSN = NULL)
=> AND (TRUE or SSN = NULL)
=> AND (TRUE)

-- In other words, this filter is "dissolved" and appears as if it never existed.
-- (in the scheme of a series of AND conditions)
于 2012-10-11T17:46:21.403 回答
0
CREATE PROCEDURE 
    MyProcedure

    @LastName Varchar(30) = NULL,
    @FirstName Varchar(30) = NULL,
    @SSN INT = -1
AS

SELECT LastName, FirstName, RIGHT(SSN,4) as SSN
FROM Employees
WHERE 
    (
        (LastName like '%' + ISNULL(@LastName, '') + '%')
            AND 
        (FirstName like '%' + ISNULL(@FirstName, '') + '%')
    )
AND
    (SSN = @SSN or @SSN = -1)

只需给 @SSN 一个默认值,您就可以一直使用 AND 并担心它。

于 2012-10-11T19:02:55.707 回答