views:

63

answers:

6

I would love to have a t-sql statement like the following...

SELECT [field]
FROM [table]
WHERE CASE @flag
        WHEN 1 THEN col1 = @value
        ELSE col2 = @different_value
      END

The point being I want to put a flag in my function to use different where clauses in the same query. I just can't get it to work. Is this possible?

A: 

Perhaps this could be of interest

http://www.sqlteam.com/article/implementing-a-dynamic-where-clause

leson
+1  A: 

With mySQL your statement should work, because mySQL supports binary expressions.

So you have to try this

SELECT [field] 
FROM [table] 
WHERE CASE @flag 
        WHEN 1 
        THEN case when col1 = @value then 1 else 0 end
        ELSE case when col2 = @different_value then 1 else 0 end 
      END = 1

That isn't pretty good readable. Please be aware of performance issues, because the optimizer may struggle here.

BeachBlocker
`optimizer may struggle here.` getting it to work and getting it to work fast (using an index) are usually quite different.
KM
+3  A: 

Will this work for you?

Where (@flag = 1 and col1 = @value) or (@flag != 1 and col2 = @different_value). 
jdot
Excellent. First pass, looks like it works. I'll continue testing, but I think this is a go. Simple too. Thanks!
Peter
there is no chance of index usage with this, unless you include OPTION(RECOMPILE) and are running on a certain release of SQL Server 2008, see this, from the links in my answer [A Tale of Service Packs and Cumulative Updates](http://www.sommarskog.se/dyn-search-2008.html#SPandCUs). This link explains how the newest releases of 2008 can recompile the query taking into consideration the run-time value of local variables. when that is done things like `(@flag = 1 and col1 = @value)` can be optimized out of the query if @flag isn't 1 and if it is 1, then optimized to be just `col1 = @value`
KM
I'm running SQL Server 2005, so I guess it won't optimize yet.
Peter
+1  A: 

Dynamically changing searches based on the given parameters is a complicated subject and doing it one way over another, even with only a very slight difference, can have massive performance implications. The key is to use an index, ignore compact code, ignore worrying about repeating code, you must make a good query execution plan (use an index).

Read this and consider all the methods. Your best method will depend on your parameters, your data, your schema, and your actual usage:

Dynamic Search Conditions in T-SQL by by Erland Sommarskog

The Curse and Blessings of Dynamic SQL by Erland Sommarskog

this will produce the best execution plan:

IF @flag=1
BEGIN
    SELECT
        [field]
        FROM [table]
        WHERE col1 = @value
END
ELSE
BEGIN
    SELECT
        [field]
        FROM [table]
        WHERE col2 = @different_value
END

However, if you have to have a single query, this is your best bet at using an index

SELECT
    [field]
    FROM [table]
    WHERE @flag=1
        AND col1 = @value
UNION ALL
SELECT
    [field]
    FROM [table]
    WHERE @flag!=1
        AND col2 = @different_value
KM
I agree. I will put these in the "must read" stack. Thanks for the reply.
Peter
It does "have" to be one query, since I'm using it as a function that that receives the @flag parameter. I'll test the union instead of the OR in the where clause as well. It's a relatively small query, so I don't know that it'll make a huge difference, but it's good to know for potential future issues with different datasets. Thanks for all the help!
Peter
A: 

You could also use boolean logic:

SELECT blah FROM myTable WHERE (@i IS NULL OR AnotherCondition)
JonH
A: 

How about simply;

WHERE
  (@flag = 1 AND col1 = @value)
OR
  (@flag = 2 AND col2 = @different_value)
...
Alex K.