Construyendo una cláusula dinámica donde no falla

He construido una interfaz, donde el usuario obtiene registros de la base de datos. El usuario tiene la opción de especificar 0 o más de los filtros. Hay cuatro filtros A, B, C, D (digamos que estos son los campos en una tabla determinada)

Así es como debería verse mi consulta:

select * from table 
where (A = v1 or B = v2 or C = v3) and D = v4

Estoy tratando de encontrar una forma de formular la consulta, mientras que cuando se especifica un filtro específico, se aplica, si no es así, se ignora. Pero esto debería ser válido para los dieciséis casos.

Lo que he podido encontrar hasta ahora son estos métodos:

select * from table
where (
    (A = v1 and 1)
    or (B =  v2 and 1)
    or (C = v3 and 1)
    )
    and D = v4

v1 u otros valores se establecen en -1 cuando no se especifican. Entonces, en caso de que no se especifiquen, simplemente se ignoran, porque entonces se usa el otro filtro (de entre A, B, C). Pero esto falla en el caso de que no se especifique nada de A, B y C. En ese caso, falso se combina con D y D no se aplica.

¿Hay alguna manera de incluir una cláusula where para este caso? También estoy abierto a soluciones programáticas para esta, donde agrego o no agrego cláusulas a través del código, pero lo preferiría de esta manera. Y realmente no me gustaría tener muchas declaraciones if-else.

¡Gracias!

preguntado el 12 de junio de 12 a las 08:06

3 Respuestas

¿Qué pasa con el uso case construir

  select * 
  from table
  where (A = CASE WHEN v1 IS NOT NULL THEN v1 else '' END)
            OR (B =  CASE WHEN v2 IS NOT NULL THEN v2 else '' END)
            OR (C = CASE WHEN v3 IS NOT NULL THEN v3 else '' END)
            OR (CASE WHEN v1 is null and v2 is null and v3 is null then 1 else 0 end)
  and D = v4

Respondido el 12 de junio de 12 a las 09:06

Entonces, cuando se especifican A y B, y C no, C = C me da verdadero, y A o B o verdadero da como resultado que A y B no se apliquen, se considerarán todas las filas. - Saad Rehman Shah

@Cafeína Sí. Acordado. He actualizado el SQL. Supongo que A, B, C son campos varchar. - ejb_guy

Solo podrías decir A = v1 or B = v2 or ... (más explicación en mi respuesta) - Andomar

if v1-v4 son los valores que está buscando y todos ellos son -1 si no se especifica, puede hacer esto:

SELECT
  *
FROM
  table
WHERE
  (
    (A = v1 OR -1 = v1)
  or 
    (B =  v2 OR -1 = v2)
  or 
    (C = v3 OR -1 = v3)
  )
AND
  (D = v4 OR -1 = v4)

Respondido el 12 de junio de 12 a las 08:06

Supongamos que especifico A y B, pero no C. En ese caso, será (A = v1 o B = v2 o verdadero) y D = v4, lo que descartará los dos primeros filtros. - Saad Rehman Shah

Las bases de datos tienen dificultades para optimizar las cláusulas where dinámicas. Por lo general, producirán un plan que sea óptimo para la primera invocación. Entonces, si su primera búsqueda es para el filtro A y B, el plan de consulta se optimizará para eso. La siguiente consulta también usará ese plan, incluso si usa los filtros C y D. Agregar cláusulas where en el código tiende a funcionar mucho mejor.

Pero es posible, por ejemplo:

where  (
           A = @FilterAValue
           or B = @FilterBValue
           or C = @FilterCValue
       )
       and D = coalesce(@FilterDValue, D)

Y luego puede alternar los filtros con el FilterXValue parámetros Si el filtro para A, B o C es null, las otras partes del or aún será evaluado. A = null or B = 1 es el mismo que unknown or B = 1 lo cual solo es cierto cuando B = 1.

Respondido el 12 de junio de 12 a las 08:06

¿Qué sucede cuando no se proporcionan A, B, C? Si no me equivoco, eso es lo que busca OP. - ejb_guy

Entonces no se devuelven filas (igual que su respuesta). Podría agregar or @FilterAValue is null and @FilterBValue is null and @FilterCValue is null debajo del ultimo or para devolver todas las filas en su lugar. - Andomar

El último caso verifica si v1, v2, v3 son nulos y luego devuelve verdadero para todas las filas, lo que hace que también se aplique el filtro D solo. O puede ser que me esté equivocando en la pregunta :-) - ejb_guy

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.