2010-07-02 39 views
5

Quiero escribir un procedimiento almacenado que funciona más o menos así:procedimiento almacenado con resultados condicionales

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

si que devuelve filas, devolver esas filas, si no, volver

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

Editar :

Se siente que debería haber una manera de crear un procedimiento tal que ejecute la primera consulta una vez y ejecuta la segunda consulta solo si es necesario.

End Edit.

Lo mejor que pude hacer fue el seguimiento, que (en teoría) se ejecuta la primera consulta dos veces, a menos que tal vez su caché:

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 

Por lo que su valor, esto es, en Microsoft SQL Server 2008

+0

¿Qué base de datos y versión? – Blorgbeard

+0

¿Y su pregunta o problema es?!?!?!? Parece que tiene un enfoque: ¿no funciona o cuál es el problema? –

+0

Si eso es SQL Server 2000, entonces ese es el mejor enfoque que conozco pero +1 porque me encantaría saber si hay otra forma. –

Respuesta

5

Esto debería evitar el acceso a la tabla adicional para la comprobación de existencia. No estoy seguro si hay una manera más ordenada.

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

Tenga en cuenta que esto funciona pero devuelve dos conjuntos de resultados. –

+1

@BC - Buen punto. –

+2

Creo que este es el mejor rendimiento, pero su aplicación tiene que mirar el segundo resultado si el primer resultado está vacío. –

-2

EDITAR La respuesta fue editado después de la pregunta fue editado.

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

Para que esto funcione de la misma manera, la parte "Y NO" debería ser "Y NO EXISTE (......) –

0

También puede hacerlo en una consulta:

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

Creo que se puede hacer esto con una variable de tabla, que debe evitar el problema de dos conjuntos de resultados. Algo así como:

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

Sin embargo, hay una sobrecarga con este enfoque al crear la variable de tabla, insertarla, y luego seleccionar de eso que puede superar cualquier beneficio potencial de evitar el cheque. Estoy empezando a pensar que el enfoque en la pregunta realmente no se puede mejorar. –

0

¿Por qué no se puede hacer esto en una sola consulta:

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 
        ) 

Otra solución única consulta:

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

Una sola consulta sí, pero el mismo o peor plan de ejecución. –

+0

@BC - No necesariamente. Podría manejar el problema de detección de parámetros mejor que con la declaración IF. – Thomas

0

No sé si ayuda a las todo en cuanto al rendimiento, pero puede probar la función con valores de tabla:

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 

Pero dudo que ayude.

En general, me quedaré con su enfoque original. Es el más simple y limpio. Y el caché y el buen índice deberían encargarse del rendimiento.

Si hubiera problemas reales de rendimiento aquí, daría un paso atrás y miraría el diseño de esta base de datos. ¿Por qué tienes nulls allí? ¿Por qué estás probando dos filtros? ¿Se puede modelar de manera diferente? Si no, ¿tal vez una pequeña desnormalización?

Cuestiones relacionadas