2010-07-02 1 views
5

Voglio scrivere una stored procedure che funziona in questo modo:stored procedure con risultati condizionali

SELECT * from T where T.A = @a and T.B = @b 

se che restituisce le righe, restituire le righe, se non, tornare

SELECT * from T where T.A = @a and T.B IS NULL 

Edit :

Sembra che ci dovrebbe essere un modo per creare una procedura tale da eseguire la prima query una volta ed esegue la seconda query solo se necessario.

Fine modifica.

il meglio che potevo gestire è stato il seguito, che (in teoria) esegue la prima query per due volte, a meno che forse la sua cache:

IF EXISTS (SELECT * from T where T.A = @a and T.B = @b) THEN 
    SELECT * from T where T.A = @a and T.B = @b 
ELSE 
    SELECT * from T where T.A = @a and T.B IS NULL 

Per quello che il suo valore, questo è in Microsoft SQL Server 2008

+0

Quale database e versione? – Blorgbeard

+0

E la tua domanda o problema è?!?!?!? Sembra che tu abbia un approccio - non funziona, o qual è il problema? –

+0

Se si tratta di SQL Server 2000, questo è l'approccio migliore che conosco ma +1 perché mi piacerebbe sapere se c'è un altro modo! –

risposta

5

Questo dovrebbe evitare l'accesso alla tabella aggiuntiva per il controllo dell'esistenza. Non sono sicuro che ci sia un modo più ordinato.

SELECT * from T where T.A = @a and T.B = @b 


IF (@@ROWCOUNT = 0) 
BEGIN 
    SELECT * from T where T.A = @a and T.B IS NULL 
END 
+1

Attenzione, questo funziona ma restituisce due set di risultati. –

+1

@BC - Buon punto. –

+2

Penso che questo sia il migliore, ma la tua applicazione deve guardare al secondo risultato se il primo risultato è vuoto. –

-2

EDIT la risposta è stata modificato dopo la questione è stato modificato.

CREATE PROCEDURE myconditionalsp 
@a <type>, 
@b <type> 
AS 

SELECT * from T 
where 
    -- the second condition is true AND the first condition is false 
    (((T.A = @a) and (T.B IS NULL)) AND NOT ((T.A = @a) and (T.B = @b))) 
    OR 
    -- the first condition is true (regardless what is the second condition) 
    ((T.A = @a) and (T.B = @b)) 
GO 
+0

Affinché funzioni allo stesso modo, la parte "AND NOT" dovrebbe essere "AND NOT EXISTS (......) –

0

si può anche fare in una query:

SELECT * from T where (T.A = @a and T.B = @b) OR 
(0=(SELECT COUNT(*) T1 where (T1.A = @a and T1.B = @b)) 
    AND T.A = @a and T.b IS NULL) 
1

Penso che si possa fare questo con una variabile di tabella, che dovrebbe evitare il problema di due gruppi di risultati. Qualcosa di simile:

declare @result1 table (...) 
insert into @result1 select * from T where T.A = @a and T.B = @b 

if (@@rowcount = 0) 
    select * from T where T.A = @a and T.B is null 
else 
    select * from @result1 
+0

C'è un overhead con questo approccio anche se si crea la variabile table, inserendola, e quindi selezionare da esso che può superare qualsiasi potenziale vantaggio di evitare il controllo Sto iniziando a pensare che l'approccio nella domanda non può essere migliorato –

0

Perché non si può fare questo in una singola query:

Select ... 
From T 
Where T.A = @a 
    And T.B = @b 
Union All 
Select ... 
From T 
Where T.A = @a 
    And T.B Is Null 
    And Not Exists (
        Select 1 
        From T 
        Where T.A = @a 
         And T.B = @b 
        ) 

Un'altra soluzione di query singola:

Select ... 
From T 
Where T.A = @a 
    And T.B = @b 
Union All 
(Select ... 
From T 
Where T.A = @a 
    And T.B Is Null 
Except 
Select ... 
From T 
Where T.A = @a 
    And T.B = @b) 
+0

Domanda singola sì, ma piano di esecuzione uguale o peggiore –

+0

@BC - Non necessariamente: potrebbe gestire meglio il problema dello snifing dei parametri rispetto all'istruzione IF. – Thomas

0

Non so se aiuta a per quanto riguarda le prestazioni, ma è possibile provare la funzione con valori di tabella:

create function fun(@a <aType>, @b <bType>) 
returns @result (<...columns...>) 
as begin 
insert into @result 
select * from T where T.A = @a and T.B = @b; 

if (@@ROWCOUNT = 0) begin 
    insert into @result 
    select * from T where T.A = @a and T.B is null; 
end; 
return; 
end; 
GO 

Ma dubito che aiuti.

In generale, vorrei attenermi al tuo approccio originale. È il più semplice e più pulito. E cache e buon indice dovrebbero prendersi cura delle prestazioni.

Se ci fossero reali problemi di prestazioni qui, vorrei fare un passo indietro e guardare questo design del database. Perché stai avendo nulla qui? Perché stai provando due filtri? Può essere modellato in modo diverso? Se no, forse un po 'di denormalizzazione?