2008-11-25 10 views
14

Estoy creando un procedimiento almacenado para devolver resultados de búsqueda donde algunos de los parámetros son opcionales.Instrucción SQL if en la cláusula where para buscar bases de datos

Quiero una "instrucción if" en mi donde cláusula, pero no puede hacerlo funcionar. El donde cláusula debería filtrar solo por los parámetros no nulos.

Aquí está el sp

ALTER PROCEDURE spVillaGet 
-- Add the parameters for the stored procedure here 
@accomodationFK int = null, 
@regionFK int = null, 
@arrivalDate datetime, 
@numberOfNights int, 
@sleeps int = null, 
@priceFloor money = null, 
@priceCeil money = null 
AS 
BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

-- Insert statements for procedure here 
select tblVillas.*, tblWeeklyPrices.price from tblVillas 
INNER JOIN tblWeeklyPrices on tblVillas.villaId = tblWeeklyPrices.villaFK 
where 
    If @accomodationFK <> null then 
     accomodationTypeFK = @accomodationFK 
    @regionFK <> null Then 
     And regionFK = @regionFK 
    IF @sleeps <> null Then 
     And sleeps = @sleeps 
    IF @priceFloor <> null Then 
     And price >= @priceFloor And price <= @priceCeil 


END 

¿Alguna idea de cómo hacer esto?

Respuesta

25
select tblVillas.*, tblWeeklyPrices.price 
from tblVillas 
INNER JOIN tblWeeklyPrices on tblVillas.villaId = tblWeeklyPrices.villaFK 
where (@accomodationFK IS null OR accomodationTypeFK = @accomodationFK) 
    AND (@regionFK IS null or regionFK = @regionFK) 
    AND (@sleeps IS null OR sleeps = @sleeps) 
    AND (@priceFloor IS null OR (price BETWEEN @priceFloor And @priceCeil)) 
+0

gracias por su ayuda, pero el valor en la base de datos no es nulo. Quiero omitir esa parte de la cláusula where si se pasa null para uno de los parámetros – mancmanomyst

+4

Por qué funciona esto: si @var es nulo, entonces toda la línea es verdadera, independientemente del resto de la línea (por lo tanto ignorada y sin filtrar)) Si no es nulo, entonces la línea es falsa * a menos que * ColVar = @ var, aplicando así el filtro. Estaba confundido la primera vez que leí este estilo de filtro, pero ahora lo uso en todos lados. –

+0

mancmanomyst.myopenid.com: eso es lo que hace. Sugiero hacer una tabla de verdad: al principio no es intuitiva. –

0

Puede también utilizar IsNull o función

Where accomodationTypeFK = IsNull(@accomodationFK, accomodationTypeFK) 
    And regionFK = Coalesce(@regionFK,regionFK) 
    And sleeps = IsNull(@sleeps,sleeps) 
    And price Between IsNull(@priceFloor, Price) And IsNull(priceCeil, Price) 

Esto hace lo mismo que la sugerencia de Michael por encima de ...

IsNull(), y se unen() funcionan más o menos Coalesce de la misma manera, devuelven el primer argumento no nulo en la lista, excepto que iSNull solo permite 2 argumentos, y Coalesce puede tomar cualquier número ...

http://blogs.msdn.com/sqltips/archive/2008/06/26/differences-between-isnull-and-coalesce.aspx

+0

¿Rompe el optimizador o es lo suficientemente inteligente como para hacer esto bien? Me pongo nervioso cuando veo comparaciones fallidas como esa. Buena mención, sin embargo. Yo uso esas funciones mucho. Otra función menos conocida es NULLIF (a, b) que devuelve null si a y b son iguales. –

+0

No estoy seguro acerca del optimizador ... confíe en el hecho de que la columna está sola en un lado del operador =, por lo que "debería" ser SARG-able. Y NullIf() es kewl también, pero no encuentro tanta oportunidad de usarlo ... –

+0

Ditto: Tenga en cuenta que, aunque esta técnica se usa comúnmente, puede tener dificultades, especialmente cuando hay una gran cantidad de opciones opcionales parámetros. Haga una búsqueda SO para 'oler parámetros' y 'planes de consultas en caché' –

0

Hemos utilizado una gran cantidad de COALESCE aquí en el pasado para "dynamic WHERE clauses" como si estuviera hablando.

SELECT * 
FROM vehicles 
WHERE ([vin] LIKE COALESCE(@vin, [vin])  + '%' ESCAPE '\') 
    AND ([year] LIKE COALESCE(@year, [year]) + '%' ESCAPE '\') 
    AND ([make] LIKE COALESCE(@make, [make]) + '%' ESCAPE '\') 
    AND ([model] LIKE COALESCE(@model, [model]) + '%' ESCAPE '\') 

Un gran problema surge de que cuando se quiere opcionalmente filtro para una columna que también es anulable ... Si los datos de la columna es null para una fila dada y el usuario no entró nada para buscar por esa columna (por lo que la entrada del usuario también es null), entonces esa fila ni siquiera aparecerá en los resultados (que, si sus filtros son opcionales, es un comportamiento de exclusión incorrecto).

Con el fin de compensar los campos con valores nulos, al final tener que hacer más desordenado SQL aspecto de este modo:

SELECT * 
FROM vehicles 
WHERE (([vin] LIKE COALESCE(@vin, [vin])  + '%' ESCAPE '\') 
     OR (@vin IS NULL AND [vin] IS NULL)) 
    AND (([year] LIKE COALESCE(@year, [year]) + '%' ESCAPE '\') 
     OR (@year IS NULL AND [year] IS NULL)) 
    AND (([make] LIKE COALESCE(@make, [make]) + '%' ESCAPE '\') 
     OR (@make IS NULL AND [make] IS NULL)) 
    AND (([model] LIKE COALESCE(@model, [model]) + '%' ESCAPE '\') 
     OR (@model IS NULL AND [model] IS NULL)) 
+0

Como recuerdo, esa es otra diferencia entre IsNull y Coalesce ... Uno de ellos (se me olvida que) exhibe este comportamiento, y el otro no .. –

+0

Ahora tengo que buscarlo ... –

+0

IsNull funciona bien aquí. Coalesce exhibe este problema. Pero también puedes resolverlo con un molde ... http://blogs.msdn.com/sqltips/archive/2008/06/26/differences-between-isnull-and-coalesce.aspx –

0

Para que lo entienda, SI es el código de procedimiento en T-SQL. No se puede usar en una instrucción de inserción/actualización/eliminación/selección; solo se puede usar para determinar cuál de las dos declaraciones desea ejecutar. Cuando necesite diferentes posibilidades dentro de una declaración, puede hacer lo anterior o usar una instrucción CASE.

-2

Intente poner su instrucción IF alrededor de toda la instrucción SQL. Eso significa que tendrá una declaración de SQL para cada condición. Eso funcionó para mí.

+1

esto podría llevar a una infierno de un montón de código duplicado. – Duncan

+0

De acuerdo con Duncan. tratando de hacer eso en un procedimiento almacenado que acepta 6 params .. – Gagan

Cuestiones relacionadas