CASE statement in a WHERE clause
-
16 เมษายน 2555 14:51
I need to parse a sproc parameter with three conditions...
1. If parameter is empty return all records
2. If parameter contains a single value, return only that record
3, If parameter contains a comma separated list, return only the records in that list.
I've got it working for conditions 1 & 2, but when I add the third condition it errors out.
Logically it's something similar to:
LEN(@PermitNumber) CASE
WHEN 0 THEN P.PermitNumber Like '%' --select all
WHEN 7 THEN P.PermitNumber = @PermitNumber -- select one
ELSE P.PermitNumber IN (SELECT * --select from list
FROM dbo.Strtotable(@PermitNumber))Any ideas?
ตอบทั้งหมด
-
16 เมษายน 2555 14:57
http://www.sommarskog.se/arrays-in-sql.htmlThanks and regards, Rishabh , Microsoft Community Contributor
- เสนอเป็นคำตอบโดย Naomi NMicrosoft Community Contributor, Moderator 16 เมษายน 2555 14:58
-
16 เมษายน 2555 15:01ผู้ดูแล
I suggest to use 2 cases
1. Parameter is empty
2. List of values (one value is also a list).
So,
IF NULLIF(@param,'') IS NULL
select * from myTable
ELSE -- list of values
select * from myTable where PermitNumber IN (select Item from dbo.fnSplit (@ListOfPermitNumbers,','))
-------------------------------------------
Where fnSplit function can be any of the split functions available, for example, check
http://www.sqlservercentral.com/articles/Tally+Table/72993/
For every expert, there is an equal and opposite expert. - Becker's Law
My blog -
16 เมษายน 2555 15:39
I have a function that takes a comma separated list and outputs a table that can be consumed by an IN clause. Both of these are helpful. But I need the logic to work in a where clause. I'm hoping not to have to have to repeat the entire select statement twice. A simplified example...
SELECT P.PermitNumber, P.ProjectName
FROM Permit P
WHERE
P.PermitNumber LIKE CASE
--single permit
WHEN LEN(RTRIM(@PermitNumber)) > 0 THEN @PermitNumber
--more than one permit
--WHEN (SELECT *
-- FROM dbo.Strtotable(@Permit))
--all permits
ELSE '%'
ENDwhen I uncomment the line which breaks the comma separated list into a table it errors out
-
16 เมษายน 2555 15:41Why not just change your function to output a table with the Permit numbers and just join to it rather than caring wether there are 1 or more than one?
Chuck
- แก้ไขโดย Chuck Pedretti 16 เมษายน 2555 15:42
-
16 เมษายน 2555 15:44
Something like this:
SELECT P.PermitNumber, P.ProjectName FROM Permit P JOIN dbo.Strtotable(@PermitNumber) plf on p.permitnumber = plf.permitnumber or @PermitNumber = ''
Chuck
- แก้ไขโดย Chuck Pedretti 16 เมษายน 2555 15:45
- แก้ไขโดย Chuck Pedretti 16 เมษายน 2555 16:01 typo
-
16 เมษายน 2555 15:47ผู้ดูแล
You can also use dynamic SQL here, e.g.
declare @SQL nvarchar(max)
create table #PermitNumbers (PermitNumber int primary key)
set @SQL = 'Here goes that static part of the complex query including parameters, if needed'
if NULLIF(@PermitNumber, '') IS NOT NULL
BEGIN
insert into #PermitNumbers select item from dbo.StrToTable (@PermitNumber)
set @SQL = @SQL + ' AND P.PermitNumber IN (select PermitNumber from #PermitNumbers)'
END
EXECUTE sp_ExecuteSQL @SQL, N'@ParamListIfNeeded', @Parameters
For every expert, there is an equal and opposite expert. - Becker's Law
My blog -
16 เมษายน 2555 15:58
Here - this works: Just mess around with the values in @PermitNumber to test
CREATE FUNCTION [dbo].[Strtotable] ( @delimited nvarchar(max) ) RETURNS @t TABLE ( permitnumber nvarchar(max) ) AS BEGIN declare @xml xml set @xml = N'<root><r>' + replace(@delimited,',','</r><r>') + '</r></root>' insert into @t(permitnumber) select r.value('.','varchar(50)') as item from @xml.nodes('//root/r') as records(r) RETURN END
CREATE TABLE #Permit(Permitnumber int, Projectname varchar(50)) INSERT #Permit Values(122,'Test1') INSERT #Permit Values(1234,'Test2') INSERT #Permit Values(123456,'Test3') DECLARE @PermitNumber varchar(max) SET @PermitNumber = '' SELECT P.PermitNumber, P.ProjectName FROM #Permit P JOIN dbo.Strtotable(@PermitNumber) plf on p.permitnumber = plf.permitnumber or @PermitNumber = ''
Chuck
- แก้ไขโดย Chuck Pedretti 16 เมษายน 2555 15:59
- ทำเครื่องหมายเป็นคำตอบโดย ChrisTheDBA919 16 เมษายน 2555 16:02
-
16 เมษายน 2555 16:08ผู้ดูแล
I don't think it's going to be a good performing solution. I recommend to compare 2 versions - the one I suggested with this version on big tables.For every expert, there is an equal and opposite expert. - Becker's Law
My blog- ทำเครื่องหมายเป็นคำตอบโดย ChrisTheDBA919 16 เมษายน 2555 16:14
-
16 เมษายน 2555 16:18
I don't think it's going to be a good performing solution. I recommend to compare 2 versions - the one I suggested with this version on big tables.
For every expert, there is an equal and opposite expert. - Becker's Law
My blog
Why would it not perform well? I'm assuming permit would be indexed on PermitNumber - also assume that they are not sending in a string with 20,000 comma delimited values. There is no reason the join would not be fast. In general I've got a absolutely no dynamic sql rule in stored procedures.Chuck
-
16 เมษายน 2555 16:21ผู้ดูแล
When we stat using OR conditions in the JOIN, it's not going to be really fast and also may end up generating wrong plan depending on the initial call. At least we may want to add OPTION (Recompile) to the query above.
See these links
Do you use ISNULL(...). Don't, it does not perform - short blog by Denis Gobo
Dynamic Search Conditions in T-SQL Version for SQL 2008 (SP1 CU5 and later) - long and comprehensive article by Erland Sommarskog
Catch All Queries - short blog by Gail ShawSunday T-SQL tip: How to select data with unknown parameter set Nice blog by Dmitri Korotkevitch
Option recompile Option recompile discussion thread
For every expert, there is an equal and opposite expert. - Becker's Law
My blog- แก้ไขโดย Naomi NMicrosoft Community Contributor, Moderator 16 เมษายน 2555 16:21
-
16 เมษายน 2555 16:23But the OR is joining against either a non indexed small table with few rows, no rows or an empty variable. Don't see any sort of performance issue in this case. The dynamic search condition problem I agree with - but that is an entirely different case where the table you are OR joining to actually contains rows.
Chuck
- แก้ไขโดย Chuck Pedretti 16 เมษายน 2555 16:23
- แก้ไขโดย Chuck Pedretti 16 เมษายน 2555 16:24
-
16 เมษายน 2555 16:28ผู้ดูแลI think it's the same case here - we either JOIN or not join at all. I can not run some performance tests now, but if you have a moment, it will be a good test to try.
For every expert, there is an equal and opposite expert. - Becker's Law
My blog