2010-04-02 14 views
7

Sto desiderando di poter fare qualcosa di simile a quanto segue in SQl Server 2005 (che so non è valido) per la mia clausola where. A volte @teamID (passato in una stored procedure) sarà il valore di un teamID esistente, altrimenti sarà sempre zero e voglio tutte le righe dalla tabella Team.Operatore condizionale in SQL Dove clausola

Ho studiato utilizzando Case e l'operatore deve venire prima o dopo l'intera istruzione che mi impedisce di avere un operatore diverso in base al valore di @teamid. Qualsiasi suggerimento diverso dalla duplicazione delle mie dichiarazioni selezionate.

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 

risposta

18

È possibile farlo senza un caso:

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

Che dire:

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

Senza utilizzare SQL dinamico, l'opzione più performante è:

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 

Utilizzo di SQL dinamico:

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 

Attenzione che sp_EXECUTESQL memorizza nella cache il piano di query, mentre EXEC no. Leggi questo: http://www.sommarskog.se/dynamic_sql.html

+1

Non credo che la complessità aggiuntiva di SQL dinamico o di due blocchi IF valga la pena, a meno che non si stia interrogando il database National Sport Association of China ;-) – Andomar

+0

Ma il guadagno di prestazioni vale la complessità e la perdita di costi di manutenzione ? – tpdi

+0

Tutte e tre le opzioni hanno i loro pro e contro - manca una parentesi nel suggerimento di Andomar, e le cose non funzioneranno come previsto. –

0

Se si potesse trattare Null come tutti i record:

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

ancora più semplice di risposta di Andomar, e supponendo che id è mai 0 (come per la maggior parte ids incremento automatico) è

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

Tale predicato è sempre true quando @teamid è zero, e altrimenti è true solo quando corrisponde a teamId di una particolare riga.

Nota comunque: funziona in modo abbastanza efficiente su Sybase 11 o successivo; ha funzionato in modo abbastanza inefficiente su MS SQL Server 2003; Non so come funziona sulla versione attuale di MS SQL Server.

Inoltre, è possibile utilizzare il caso; devi solo mettere il caso in cui clausola, non la clausola where nel caso. Così la vostra query originale potrebbe essere:

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

Si noti che questo è probabile che sia meno efficiente, tuttavia, come deve essere valutata per ogni riga e sarà anche probabile risultato in una scansione completa della tabella.

Il modulo che ho fornito sopra è più probabile che venga riscritto da uno smart query optimizer (il tuo chilometraggio dipende dal tuo RDBMS) per usare un indice quando @teamid non è zero.

+0

+1 La tua prima risposta è fantastica. Anche più semplice potrebbe essere '@teamid in (0, TeamID)'! – Andomar

+0

Grazie! Ma l'utilizzo di una lista non probabilmente non si tradurrà in ottimizzazione. – tpdi

+0

Un elenco è solo zucchero sintattico. Penso che 'a in (b, c)' sia esteso a 'a = b o a = c' prima che l'ottimizzatore possa vederlo – Andomar