Reputation: 247
I'm trying to create a stored procedure that allows parameters to be omitted, but ANDed if they are provided:
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)
I only want to do the AND if there's an @SSN provided. Or is there some other way to do this?
If an SSN is provided, all records are returned by the LastName/FirstName part of the query. If just a lastname/firstname is provided, the AND makes it so no records are returned since the SSN won't validate.
Ideas?
Additional Clarification
Assume a basic recordset:
First Last SSN
Mike Smith 123456789
Tom Jones 987654321
IF we ALTER the Procedure above so it doesn't include this chunk:
AND
(SSN = @SSN)
then everything works great, provided we're passed a FirstName or LastName. But I want to be able to include SSN, if one is provided.
If I change the AND to an OR, then I get a bad result set since the FirstName/LastName portion of the query evalute to:
WHERE (LastName like '%%' and FirstName like '%%')
(which will, of course, return all records)
If I can't conditionally abort the AND, I'm hoping for something like:
AND
(SSN like ISNULL(@SSN, '%'))
:-)
Upvotes: 7
Views: 12062
Reputation: 1193
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)
Just give @SSN a default value and you can use the AND all the time and worry about it.
Upvotes: 0
Reputation: 107716
HERE's THE BIBLE on dynamic search parameters in SQL Server. You should write it like this
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)
BTW, there's no such thing as a short circuit boolean in SQL Server. Yes it does stop at the first conclusion, but there's no guarantee the condition on the left is processed before the right. e.g. this code is NOT SAFE. I'm using 'ABC.123' but that could just as well be a column.
WHERE ISNUMERIC('ABC.123') = 1 OR CAST('ABC.123' AS INT) > 10
To illustrate on the AND (@SSN is null or SSN = @SSN)
clause, for when @SSN is not provided, i.e. 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)
Upvotes: 0
Reputation: 1212
You could put both versions of the statement in an if block.
AS
IF @SSN IS NULL
/*regular statement*/
ELSE
/*Statement with @SSN*/
or
AND
SSN = ISNULL(@SSN, SSN)
I have never used the 2nd option but I know it exists.
Upvotes: 0
Reputation: 171411
Change:
AND (SSN = @SSN)
to:
AND (SSN = @SSN or @SSN is null)
If SSN
is never null, you could also do:
AND SSN = ISNULL(@SSN, SSN)
Upvotes: 17