I need to create a stored procedure which takes 12 arguments and the query is filtered with a different combination of this arguments. All 12 arguments are not mandatory as if I pass 3 or 5 or 12 arguments depends on search inputs entered by user.
I can create 2 ways, either using a dynamic SQL query or using 'Case where' statements. Example of these queries are as below:
Dynamic Query
DECLARE @sql VARCHAR(MAX) DECLARE @condition VARCHAR(MAX)='' Declare @var1 varchar(10) Declare @var2 varchar(10) Declare @var3 varchar(10) SET @sql='SELECT * FROM TableDemo1 TD1 WITH(NOLOCK) INNER JOIN TableDemo2 TD2 ON TD1.Column1=TD2.Column2' if(@var1 <>0 and @var1 is not null) begin if(@condition<>'') begin set @condition=@condition + ' and TD1.columnTest1='+@var1) end else begin set @condition=' where TD1.columnTest1='+@var1 end end if(@var2 <>0 and @var2 is not null) begin if(@condition<>'') begin set @condition=@condition + ' and TD2.columnTest2='+@var2) end else begin set @condition=' where TD2.columnTest2='+@var2 end end if(@var3 <>0 and @var3 is not null) begin if(@condition<>'') begin set @condition=@condition + ' and TD1.columnTest3='+@var3) end else begin set @condition=' where TD1.columnTest3='+@var3 end end SET @sql=@sql+@condition EXEC(@sql)Query with CASE WHERE
Declare @var1 varchar(10) Declare @var2 varchar(10) Declare @var3 varchar(10) SELECT * FROM TableDemo1 TD1 WITH(NOLOCK) INNER JOIN TableDemo2 TD2 ON TD1.Column1=TD2.Column2 WHERE (CASE WHEN (@var1<>0 and @var1 is not null) THEN CASE WHEN TD1.columnTest1=@var1 THEN 1 ELSE 0 END ELSE 1 END)=1 AND (CASE WHEN (@var2<>0 and @var2 is not null) THEN CASE WHEN TD2.columnTest2=@var2 THEN 1 ELSE 0 END ELSE 1 END)=1 AND (CASE WHEN (@var3<>0 AND @var3 IS NOT NULL) THEN CASE WHEN TD1.columnTest3 = @var3 THEN 1 ELSE 0 END ELSE 1 END) =1
This is just part of my stored procedure, there are 7-8 tables with joins and as above in query variety in conditions.
If I use a dynamic query, SQL Server will have to create an execution plan every time, but if I use 'case where' it also makes the query slow.
I am aware of disadvantages of dynamic SQL, but which technique I should use?
Generally it depends, but most often I use dynamic queries as a last resort. Regarding your question, I would most probably go with the CASE solution, but I think your CASE expressions are unnecessarily complicated. I would replace the WHERE clause with something like this:
...
WHERE
TD1.columnTest1 = COALESCE(NULLIF(@var1, 0), TD1.columnTest1)
AND
TD2.columnTest2 = COALESCE(NULLIF(@var2, 0), TD2.columnTest2)
AND
TD1.columnTest3 = COALESCE(NULLIF(@var3, 0), TD1.columnTest3)
With proper indexing this shouldn't be too slow.
The dynamic query will lead to an index scan.
The case will lead to a seq scan (i.e. read the whole table).
So definitely go with the dynamic query.
In my experience a dynamic where clause provides better performance. Especially over large datasets.
And a very good explanation is in Catch All Queries.
I have used the option "Andriy M" posted using coalesce and nullif functions.
But this option works only with the '=' operator, yet to find how to use it with other conditions, one example is using the 'IN' keyword.
TD1.columnTest1 = (
CASE
WHEN (
( TD1.columnTest1
IN (
SELECT item FROM dbo.Splitfunction(@comaSepValues,',')
)
)
OR
NULLIF(@PlaceTypeCode,'') IS NULL
) THEN columnTest1
ELSE NULL
END
)
Let me know if this works or not.
There are two ways to execute dynamic query 1. Exec 2. sp_executeSQL
if you want to reuse your execution plan, then go for sp_executeSQL option.
'SP_ExecuteSQL' accepts parameters, so you can directly pass your parameter to this query which will intern reuse your execution plan.
Dynamic queries are not always in bad performance specially when you are using it appropriately
来源:https://stackoverflow.com/questions/6016475/what-is-better-dynamic-sql-or-where-case