views:

296

answers:

5

I'm wishing I could do something like the following in SQl Server 2005 (which I know isnt valid) for my where clause. Sometimes @teamID (passed into a stored procedure) will be the value of an existing teamID, otherwise it will always be zero and I want all rows from the Team table.

I researched using Case and the operator needs to come before or after the entire statement which prevents me from having a different operator based on the value of @teamid. Any suggestions other than duplicating my select statements.

    declare @teamid int
    set @teamid = 0

    Select Team.teamID From Team
      case @teamid
         when 0 then 
            WHERE Team.teamID > 0
         else
            WHERE Team.teamID = @teamid
      end 
+6  A: 

You can do that without a case:

SELECT  Team.teamID 
FROM    Team
WHERE   (@teamid = 0 AND Team.teamID > 0)
        OR (@teamid <> 0 AND Team.teamID = @teamid)
Andomar
Thats the money, I knew I just wasnt being creative enough. Thanks as well Program.X.
Marc
+2  A: 

What about:

Select Team.teamID From Team Where (@teamid=0 and team.teamID>0) or (@teamid<>0 and team.teamid=@teamid)
Program.X
+3  A: 

Without using dynamic SQL, the most performant option is:

IF @teamid = 0
  BEGIN

    SELECT t.teamid
      FROM TEAM t
     WHERE t.teamid > 0

  END
ELSE
  BEGIN

    SELECT t.teamid
      FROM TEAM t
     WHERE t.teamid = @teamid

  END

Using Dynamic SQL:

DECLARE @SQL NVARCHAR(4000)
   SET @SQL = 'SELECT t.teamid
                 FROM TEAM t
                WHERE 1 = 1 '

   SET @SQL = @SQL + CASE @teamid
                       WHEN 0 THEN ' AND t.teamid > 0 '
                       ELSE ' AND t.teamid = @teamid '
                     END

BEGIN

  EXEC sp_EXECUTESQL @SQL N'@teamid INT', @teamid

END

Beware that sp_EXECUTESQL caches the query plan, while EXEC will not. Read this: http://www.sommarskog.se/dynamic_sql.html

OMG Ponies
Wouldn't t think the added complexity of dynamic SQL or two IF blocks is worth it, unless you're querying the National Sport Association of China database ;-)
Andomar
But is the performance gain worth the complexity and maintainance cost loss?
tpdi
OMG Ponies
A: 

If you could treat Null as all records:

WHERE Team.teamID = ISNULL(@teamid, Team.teamID)
Jeff O
+1  A: 

Even simpler than Andomar's answer, and assuming that id is never 0 (as for most auto-increment ids) is

SELECT  Team.teamID 
FROM    Team
WHERE   @teamid = 0 or Team.teamID = @teamid;

That predicate is always true when @teamid is zero, and otherwise only true when it matches a particular row's teamId.

Note however: this works pretty efficiently on Sybase 11 or above; it worked pretty inefficiently on MS SQL server 2003; I don't know how it works on the current version of MS SQL Server.

Also, you can use case; you just have to put the case in where clause, not the where clause in the case. So your original query would be:

Select Team.teamID 
From Team
where 
   case when @teamid = 0 then 0 else Team.teamID end = @teamId;

Note that this is likely to be less efficient, however, as it must be evaluated per row and will also likely result in a full table scan.

The form I gave above is more likely to be rewritten by a smart query optimizer (your mileage depends on your RDBMS) to use an index when @teamid is not zero.

tpdi
+1 Your first answer is awesome. Even simpler might be `@teamid in (0, TeamID)` !
Andomar
Thanks! But using an inlist will probably not result in optimization.
tpdi
@tpdi: An in list is just syntactic sugar. I think `a in (b,c)` is expanded to `a=b or a=c` before the optimizer gets to see it
Andomar