views:

89

answers:

4

Hello All,

How can I do the following in SQL Server

DECLARE @Local nvarchar(20)
SET @Local = 'True'

    SELECT * FROM My_Table
    WHERE my_ID IN

    (IF @Local = 'True' 
         SELECT AllIDs FROM ATable
    ELSE 
         SELECT TeamIDs FROM TeamTable
    )
+1  A: 
SELECT  *
FROM    mytable
WHERE   my_id IN
        (
        SELECT  allids
        FROM    atable
        WHERE   @Local = 'True'
        )
UNION ALL
SELECT  *
FROM    mytable
WHERE   my_id IN
        (
        SELECT  teamids
        FROM    teamtable
        WHERE   COALESCE(@Local, '') <> 'True'
        )

The optimizer will optimize away the wrong query, so the performance will as that of the corresponding (remaining) query.

Quassnoi
+1  A: 
DECLARE @Local nvarchar(20)
SET @Local = 'True'

SELECT * FROM My_Table
WHERE my_ID IN ( 
     SELECT AllIDs FROM ATable
     WHERE @Local = 'True'
     UNION ALL 
     SELECT TeamIDs FROM TeamTable
     WHERE @Local != 'True'
)
Roland Bouman
+2  A: 

Go for a union :-

SELECT * FROM My_Table WHERE my_id IN
(
  SELECT AllIDs AS MyIDs FROM ATable WHERE @Local = 'True'
  UNION
  SELECT TeamIDs AS MyIDs FROM TeamTable WHERE @Local <> 'True'
)
Paul Alan Taylor
+1  A: 

Don't do this!

(at least not if you care about performance)

There is certainly a way of doing this, but you really shouldn't - the reason being that (in general) a single statement has only 1 execution plan, however you essentially have 2 (potentially very different) requests:

SELECT * FROM My_Table
WHERE my_ID IN (SELECT AllIDs FROM ATable)

SELECT * FROM My_Table
WHERE my_ID IN (SELECT AllIDs FROM TeamTable)

Combining these two queries means that SQL server is forced to try and optimise both of these at the same time using only 1 exectuion plan. Depending on how different the two tables are this might work fine, or it might go horrily horrily wrong.

For example, if ATable contains only 1 row, while TeamTable contains all of the ids in My_Table then SQL server has to choose / compromise between doing a lookup (best if using ATable) and a table scan (best if using TeamTable) - whatever it ends up doing it's not possible for SQL server to execute both queries using the optimal execption plan (unless both execution plans happen to be the same).

You should use 2 statements instead:

DECLARE @Local nvarchar(20)
SET @Local = 'True'

IF @Local = 'True' 
    SELECT * FROM My_Table
    WHERE my_ID IN (SELECT AllIDs FROM ATable)
ELSE
    SELECT * FROM My_Table
    WHERE my_ID IN (SELECT AllIDs FROM TeamTable)

In fact in this particular case you might be better off selecting the list of ID's into a temporary table instead.

Kragen
`SQL Server`'s optimizer is smart enough to optimize two queries separately, even if they are within a single `UNION`.
Quassnoi
@Quassnoi - No its not, I've done some testing on the StackOverflow data dump and the execution plans shows that it either does a clustered index scan when returning a single row, or a series of cluestered index seeks when an index scan is more efficient.
Kragen
In fairness however, the impact on performance isn't as disasterous as I was expecting.
Kragen
@Kragen: you want to say that the parts of the plan for two queries combined with a `UNION ALL` differs from the plans for the very same queries parsed separately?
Quassnoi