Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase 12»»

case statement and where clause Expand / Collapse
Author
Message
Posted Friday, May 15, 2009 7:40 AM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Tuesday, September 25, 2012 12:36 PM
Points: 24, Visits: 183
I am trying to find more efficient way of writing this query.

There are two input parameters eg. @Type (4 different Type + Null
) and @value.

Depending on the Type and value data retrieve is filtered.

Select * from tableA
where case when @Type = Lname then Lname = @Value
when @type = fName then Fname = @Value
and so on....
Currently I have a logic in place as if then else...
If @Type = 'Lname'
Begin
select * from tableA
where Lname = @Value
End
else If @Type = 'Fname'
Begin
select * from tableA
where Fname = @Value
end
else if @type is null
begin select * from TableA
end

TIA,
Natasha
Post #717900
Posted Friday, May 15, 2009 7:51 AM
Old Hand

Old HandOld HandOld HandOld HandOld HandOld HandOld HandOld Hand

Group: General Forum Members
Last Login: Today @ 6:46 AM
Points: 328, Visits: 1,851
the following should help:

Select * 
from tableA
where case
when @Type = 'Lname' then Lname
when @Type = 'fName' then Fname
when @Type is null then .....
else .....
end = @Value

Notice how the @Type evaluates to a column name, then the entire case statement is then compared to @value
Post #717915
Posted Friday, May 15, 2009 8:04 AM


SSCrazy Eights

SSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy Eights

Group: General Forum Members
Last Login: Saturday, May 04, 2013 11:13 AM
Points: 9,855, Visits: 9,374
Natasha:

That's actually not a bad way to go. Your instinct might be to combine all of these into one big master query that uses the parameters to logically switch the WHERE conditions, but that is almost always a bad idea. Logical search conditions that get "switched" on and off are not handled well by the query optimizer because it has to come up with one plan that covers all of these possible conditions. Consequently, it tends to pick a plan that always runs slowy, but always works, like a table scan. So ultimately, using IF to switch the search conditions is actually better than using CASE or other WHERE expressions.

The only problem is that having all of these different queries together in one stored procedure might result in an execution plan that does not take all of them into account well, however, most of the time that I have checked one of these they seemed to use the right query plan.


-- RBarryYoung, (302)375-0451 blog: MovingSQL.com, Twitter: @RBarryYoung
Proactive Performance Solutions, Inc.
"Performance is our middle name."
Post #717932
Posted Friday, May 15, 2009 8:25 AM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Tuesday, February 12, 2013 9:06 PM
Points: 417, Visits: 265
RBarryYoung (5/15/2009)
Natasha:

Logical search conditions that get "switched" on and off are not handled well by the query optimizer because it has to come up with one plan that covers all of these possible conditions. Consequently, it tends to pick a plan that always runs slowy, but always works, like a table scan. So ultimately, using IF to switch the search conditions is actually better than using CASE or other WHERE expressions.


I'm totally agree with Barry.... using the IF is a better approach ....
Post #717959
Posted Friday, May 15, 2009 8:28 AM


SSCrazy Eights

SSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy Eights

Group: General Forum Members
Last Login: Saturday, May 04, 2013 11:13 AM
Points: 9,855, Visits: 9,374
Here's a script demonstrating the problem, using your current code example, Natasha, along with the code that Sam provided showing how to get CASE into the WHERE clause:
--====== First Create TableA and add indexes: ======
Create Table TableA (
ID int identity(1,1) primary key
, Lname varchar(255)
, Fname varchar(255)
)
Create index idxTableA_Fname on TableA(Fname)
Create index idxTableA_Lname on TableA(Lname)
go

--====== Now Load it with data: ======
Insert into TableA (Lname, Fname)
Select [name], [name]
from master.sys.syscolumns
go

--====== Create the IF based stored procedure ======
Create Proc spGet_TableA(@type as varchar(20), @value varchar(255))
AS
Begin
If @Type = 'Lname'
Begin
select * from tableA
where Lname = @Value
End
else If @Type = 'Fname'
Begin
select * from tableA
where Fname = @Value
end
else if @type is null
begin select * from TableA
end
End
go

--====== Create the CASE based stored procedure ======
Create Proc spGet_TableA_case(@type as varchar(20), @value varchar(255))
AS
Begin
Select *
from tableA
where case
when @Type = 'Lname' then Lname
when @Type = 'fName' then Fname
when @Type is null then Null
end = @Value
End
go

--====== Now Execute Both ======
--(actually, you should select these lines and user "Control-L"
-- to display the query plans)
EXEC spGet_TableA 'Lname', 'id'
go
EXEC spGet_TableA_case 'Lname', 'id'
go

If you display the query plans for the two EXEC's at the end, you will see that while you original query uses a different index, depending on the @Type parameter, the combined query has a plan that just always scans the table.

I have attached the query plans from my system for convenience.

(EDIT: the attachment had the wrong plan in it. I have corrected this.)


-- RBarryYoung, (302)375-0451 blog: MovingSQL.com, Twitter: @RBarryYoung
Proactive Performance Solutions, Inc.
"Performance is our middle name."


  Post Attachments 
Problem with Switch conditions in WHERE.zip (17 views, 3.66 KB)
Post #717961
Posted Friday, May 15, 2009 8:34 AM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Tuesday, September 25, 2012 12:36 PM
Points: 24, Visits: 183
Thank you to both of you. I was thinking the same that using if then else will be more efficient than case since case does not use indexes and majority of the time table scan is performed. With case code has clarity in reading as oppose to bunch of if then else statements but in programming world efficiency is a priority.
Once again thank you both for convincing me about my original code
Natasha
Post #717966
Posted Friday, May 15, 2009 11:53 AM
Valued Member

Valued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued Member

Group: General Forum Members
Last Login: Wednesday, April 27, 2011 12:59 AM
Points: 61, Visits: 898
You could also consider the option of dynamic querying

create table tableA (Lname varchar(10), Fname varchar(10)) 

insert into tableA (Lname,Fname) select 'a1','b1' union select 'a2','b2'

--select * from tableA

declare @Type varchar(10),
@value varchar(10),
@sqlstr nvarchar(100);

set @Type = 'Lname';
set @value = 'a2';

set @sqlstr = 'select * from tableA ';

If @Type = 'Lname'
Begin
set @sqlstr = @sqlstr + ' where Lname = ''' + @value + ''''
End
else If @Type = 'Fname'
Begin
set @sqlstr = @sqlstr + ' where Fname = ''' + @value + '''';
end

print @sqlstr
exec sp_executesql
@stmt = @sqlstr,
@params = N'@value varchar(255)',
@value = @value;


Post #718154
Posted Friday, May 15, 2009 12:00 PM


SSCrazy Eights

SSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy EightsSSCrazy Eights

Group: General Forum Members
Last Login: Saturday, May 04, 2013 11:13 AM
Points: 9,855, Visits: 9,374
gyessql (5/15/2009)
You could also consider the option of dynamic querying

I am a big proponent of dynamic SQL, but I would not recommend it, because it not necessary for these cases unless the IF..ELSE structure proves inadequate. Plus, dynamic SQL introduces other problems, especially having to protect against SQL Injection attacks.


-- RBarryYoung, (302)375-0451 blog: MovingSQL.com, Twitter: @RBarryYoung
Proactive Performance Solutions, Inc.
"Performance is our middle name."
Post #718161
Posted Saturday, March 27, 2010 4:41 AM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Wednesday, February 01, 2012 9:18 PM
Points: 22, Visits: 42
We can use case statement in where clause as follows:

declare @x int

Select col1,col2
from table1
where col1 = case when @x = 1 then 1000
when @x = 2 then 5000
end


Regards,
Tatoba
Post #891270
Posted Saturday, March 27, 2010 8:01 AM


SSChampion

SSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampion

Group: General Forum Members
Last Login: Today @ 5:10 PM
Points: 10,989, Visits: 10,535
One more alternative, that is optimized well:
SELECT  *
FROM TableA
WHERE @Type = 'Lname'
AND Lname = @Value

UNION ALL

SELECT *
FROM TableA
WHERE @Type = 'Fname'
AND Fname = @Value

UNION ALL

SELECT *
FROM TableA
WHERE @Type IS NULL;

The constant checks on @Type become start-up filters in the plan, so the parts of the UNION that don't match at run time are not actually executed at all.




Paul White
SQL Server MVP
SQLblog.com
@SQL_Kiwi
Post #891286
« Prev Topic | Next Topic »

Add to briefcase 12»»

Permissions Expand / Collapse