views:

93

answers:

3

Environment: SQL Server 2005

I have a stored proc which receives comma separated value in one parameter. I have written a Table Valued UDF function in SQL to break it and and return me it as a table. I am using that value to filter the data in the where clause of the stored proc. Everything works fine until there is NULL in that comma separated variable passed to the stored proc. I want to write my where clause in such a way that if the variable passed is NULL then it should not use the Split function. Here is what i am doing in the stored proc.

Declare @list varchar(100), @Col2 varchar(100)

SELECT  *
  FROM  Table1 t1
INNER JOIN dbo.Table2 t2 ON t1.Col1 = t2.Col1
WHERE t1.Col2 = ISNULL(@Col2,t1.Col2)
--I want to write below condition the same way i have written the above condition
    AND t1.Col3 IN (select * from dbo.SplitMe(@list))

Is there a way to write the condition to select Col3 the way Col2 is being selected?

+1  A: 

If the idea is to not filter by Col3 if @list is null then you could do it the same way

Declare @list varchar(100), @Col2 varchar(100)

SELECT  *
  FROM  Table1 t1
INNER JOIN dbo.Table2 t2
on t1.Col1 = t2.Col1

where t1.Col2 = ISNULL(@Col2,t1.Col2)
AND (@list IS NULL OR  t1.Col3 IN (select * from dbo.SplitMe(@list)))

but it would not be a good idea unless the tables are very small. For plan caching reasons it is usually best to break all these permutations into their own SQL statements rather than try and write a one size fits all query or (if the number of permutations gets too large) consider using dynamic SQL (see Dynamic Search Conditions in T-SQL)

Note this doesn't guarantee that the Split function won't get called. There is no guaranteed order of evaluation of the clauses. But it does mean that if it does get called it will have no effect on the outcome of the query. (Edit assuming of course that being called when NULL doesn't actually cause some sort of error c.f. Remus's comment)

Martin Smith
Relying on boolean operator short circuit in SQL is very dangerous, as it is **not** guaranteed: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/
Remus Rusanu
this is what i was looking for. Thanks a lot. As of now i will go with this but if performance will suck, i will change it to the dynamic query to see if it improves.
Asdfg
+1  A: 

You have a query with now two variables that are independent of one another. Including both of them in a single query produces a non-sargable query - the query is very different depending on the variable values and you're using expensive conditional expressions to keep it together. It's both a pain to maintain, and performs poorly.

You could use an IF statement:

IF
BEGIN

    SELECT *
       FROM TABLE1 t1
       JOIN TABLE2 t2 ON t2.col1 = t1.col1
     WHERE t1.col1 = COALESCE(@col2, t1.col2)

END
ELSE
BEGIN

    SELECT *
       FROM TABLE1 t1
       JOIN TABLE2 t2 ON t2.col1 = t1.col1
      WHERE t1.col2 = COALESCE(@col2, t1.col2)
          AND t1.col3 IN (SELECT * FROM dbo.splitme(@list))

END

...but there's still the null handling. For two variables, that's four possible value outcomes. Situations like these are what dynamic SQL is intended - to construct the query necessary because lugging baggage doesn't perform well.

OMG Ponies
I know this is a good candidate for dynamic SQL but i prefer writing clean SQL. Also the number of parameters are not restricted to 2 so i dont think writing SQL for every permutation and combination is a good idea. correct me if i am wrong.
Asdfg
@Asdfg: When you have two or more parameters, the possible combinations increases by squaring the # of parameters: 2 becomes 4 possibilities, 3 means 9, etc. The more possibilities, the more likely a query cache will provide little to no benefit in the non-dynamic approach. That's besides the impact of OR and other conditional logic embedded into the SQL. Dynamic SQL *is* clean SQL - it's only what actually needs to be run, not all the baggage to handle various cases. The more parameters there are, the better dynamic SQL will perform vs the answer you've selected.
OMG Ponies
A: 
WHERE (t1.Col2 = @Col2 OR @Col2 IS NULL)
AND (t1.Col3 IN (select * from dbo.SplitMe(@list)) OR @list IS NULL)
Anthony Faull