Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

T-SQL use different WHERE clause based on value of input parameter

I would like to change the WHERE clause of a query based upon the value of an input parameter. I'm guessing this is possible, but it seems that I'm approaching it in the wrong way?

A simplified version on my SP query:

CREATE PROCEDURE [dbo].[GetMailboxMessagesByStatus]
    @UserId             UNIQUEIDENTIFIER,
    @MessageStatus      INT
AS
BEGIN
    SELECT  * 
    FROM  MailboxMessages m
    WHERE
    CASE @MessageStatus
        WHEN 4 THEN m.SenderId = @UserId    --Sent
        ELSE m.RecipientId = @UserId        --Inbox
    END
END 
GO
like image 827
PixelPaul Avatar asked Jul 02 '17 21:07

PixelPaul


People also ask

Can we use two WHERE clause in SQL?

You can specify multiple conditions in a single WHERE clause to, say, retrieve rows based on the values in multiple columns. You can use the AND and OR operators to combine two or more conditions into a compound condition. AND, OR, and a third operator, NOT, are logical operators.

Can we pass parameter in with clause?

Solution 1. You can use parameters in a WITH clause just like in a traditional statement. The problem in the example is the IN operator which requires a list of values.

Can we use variable in WHERE clause in SQL?

You can't use a variable in an IN clause - you need to use dynamic SQL, or use a function (TSQL or CLR) to convert the list of values into a table.

Can WHERE clause have multiple values?

The IN operator allows you to specify multiple values in a WHERE clause. The IN operator is a shorthand for multiple OR conditions.


3 Answers

No need for case or iif constructs:

WHERE @MessageStatus = 4  AND  m.SenderId = @UserId
   OR @MessageStatus <> 4 AND  m.RecipientId = @UserId

EDIT: Be aware on big tables using this construct when the table being queried is quite large. Using 2 seperate queries using a IF statement like Chester Lim suggested might be the better solution. Preventing parameter sniffing might also be a good idea

like image 155
MWillemse Avatar answered Oct 18 '22 06:10

MWillemse


Use an IF statement.

CREATE PROCEDURE [dbo].[GetMailboxMessagesByStatus]
    @UserId UNIQUEIDENTIFIER ,
    @MessageStatus INT
AS
    BEGIN

        IF ( @MessageStatus = 4 )
            BEGIN
                SELECT  *
                FROM    MailboxMessages
                WHERE   m.SenderId = @UserId;    --Sent
            END;

        ELSE
            BEGIN
                SELECT  *
                FROM    MailboxMessages m
                WHERE   m.RecipientId = @UserId;        --Inbox
            END; 

    END;

GO

EDIT - a much better way provided by LukStorms (since i did not know IIF until i saw his answer)

CREATE PROCEDURE [dbo].[GetMailboxMessagesByStatus]
    @UserId UNIQUEIDENTIFIER ,
    @MessageStatus INT
AS
    BEGIN
        SELECT  *
        FROM    MailboxMessages m
        WHERE IIF (@MessageStatus = 4, m.SenderId, m.RecipientId) = @UserId;    --Sent
    END       
GO
like image 42
Chester Lim Avatar answered Oct 18 '22 05:10

Chester Lim


You could change that WHERE clause to

WHERE (CASE WHEN @MessageStatus = 4 THEN m.SenderId ELSE m.RecipientId END) = @UserId

Because what you put after the THEN in a CASE should just be a value, not a comparison.

Or use IIF instead of a CASE:

WHERE IIF(@MessageStatus = 4,m.SenderId,m.RecipientId) = @UserId

But the SQL will run more efficient if you use an IF ... ELSE ... and run a different Query based on the @MessageStatus.

Was writing an example for that, but Chester Lim already beat me to it. ;)
(so no need to repeat that approach in this answer)

like image 2
LukStorms Avatar answered Oct 18 '22 07:10

LukStorms