2010-04-02 21 views
7

Estoy deseando poder hacer algo como lo siguiente en SQl Server 2005 (que sé que no es válido) para mi cláusula where. Algunas veces @teamID (pasado a un procedimiento almacenado) será el valor de un ID de equipo existente, de lo contrario siempre será cero y quiero todas las filas de la tabla de Equipo.Operador condicional en SQL Donde Cláusula

Investigué usando Case y el operador debe venir antes o después de la declaración completa, lo que me impide tener un operador diferente basado en el valor de @teamid. Cualquier sugerencia que no sea la de duplicar mis declaraciones seleccionadas.

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 

Respuesta

18

Usted puede hacer eso sin un caso:

SELECT Team.teamID 
FROM Team 
WHERE (@teamid = 0 AND Team.teamID > 0) 
     OR (@teamid <> 0 AND Team.teamID = @teamid) 
2

¿Qué hay de:

Select Team.teamID From Team Where (@teamid=0 and team.teamID>0) or (@teamid<>0 and [email protected]) 
5

Sin utilizar SQL dinámico, la opción mas potente es:

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 

Usando SQL dinámico:

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 

Tenga en cuenta que sp_EXECUTESQL almacena en caché el plan de consulta, mientras que EXEC no lo hará. Leer esto: http://www.sommarskog.se/dynamic_sql.html

+1

No creo que valga la pena la complejidad añadida de SQL dinámico o dos bloques IF, a menos que esté consultando la base de datos de la Asociación Nacional de Deportes de China ;-) – Andomar

+0

¿Pero la ganancia de rendimiento vale la complejidad y la pérdida de costes de mantenimiento? ? – tpdi

+0

Las tres opciones tienen sus pros y contras: omita un corchete en la sugerencia de Andomar, y las cosas no funcionarán como se esperaba. –

0

Si usted podría tratar nulo ya que todos los registros:

WHERE Team.teamID = ISNULL(@teamid, Team.teamID) 
2

aún más simple que la respuesta de Andomar, y suponiendo que la identificación nunca es 0 (como para la mayoría de los identificadores de incremento automático) es

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

Ese predicado siempre es verdadero cuando @teamid es cero, y de lo contrario solo es verdadero cuando coincide con el ID de equipo de una fila en particular.

Sin embargo, tenga en cuenta que esto funciona bastante eficientemente en Sybase 11 o superior; funcionó bastante ineficiente en MS SQL Server 2003; No sé cómo funciona en la versión actual de MS SQL Server.

Además, puede utilizar el estuche; solo tiene que poner el caso en la cláusula where, no en la cláusula where en el caso. Por lo que su búsqueda original sería:

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

Tenga en cuenta que esto es probable que sea menos eficiente, sin embargo, ya que debe ser evaluado por fila, y también probablemente a un escaneo completo de tabla.

El formulario que proporcioné anteriormente tiene más probabilidades de ser reescrito por un optimizador de consultas inteligentes (su kilometraje depende de su RDBMS) para usar un índice cuando @teamid no es cero.

+0

+1 Su primera respuesta es asombrosa. ¡Incluso más simple podría ser '@teamid in (0, TeamID)'! – Andomar

+0

Gracias! Pero el uso de una lista de entrada probablemente no dé como resultado la optimización. – tpdi

+0

Una lista es simplemente azúcar sintáctica. Creo que 'a in (b, c)' se expande a 'a = b o a = c' antes de que el optimizador llegue a verlo – Andomar