Duda consulta SQL

Czhincksx

Tengo que hacer una búsqueda usando un procedimiento almacenado que recibe varios campos. Cada uno de ellos puede ser nulo y no se tendría en cuenta en la búsqueda. Lo que hice tenía sentido en mi cabeza pero no funcionaba bien porque por lo visto SQL no garantiza el orden de ejecución de las dos partes de un OR.

SELECT
...bla bla bla
FROM bla bla bla
WHERE
    (@Email is null OR customer.Email = @Email) AND
    (@PosCode is null OR customer.PostCode = @PostCode) AND
    (@Name is null OR customer.Name= @Name) AND
    (@Surname is null OR customer.Surname= @Surname)

Para mí esto iba así: Si el email venía a NULL el OR ya se cumplía y por tanto no lo comparaba con el del customer. Si era distinto de null entonces sí lo comparaba con el del Customer. Así para todos los parámetros. Pero por lo visto no va. ¿Cómo puedo hacerlo? Gracias.

Grise

(CASE WHEN @email is null THEN true ELSE customer.Email = @Email) AND...

Es ineficiente de la hostia, pero es la guarrada que quieres hacer tú. Es más apañado que lo hagas con COALESCE:

customer.email = COALESCE(@Email, '') AND ...

1 1 respuesta
Czhincksx

#2 Muchas gracias.

¿Pero con COALESCE qué sucederá cuando email sea null? ¿No intentará comparar customer.email con '' y fallará el AND?

1 respuesta
Ranthas

#3 Pues que te devolverá ''.

COALESCE devuelve el primer valor que no sea nulo de los que le pases, por lo que si en este ejemplo @Email es nulo, pillará el siguiente valor, que es ''. Entonces, comparará customer.email con ''.

1 respuesta
Czhincksx

#4 Entonces no me vale porque si no paso parámetro de email para la búsqueda intentará comparar los emails de los clientes con '' y sólo devolverá los clientes sin email.

Si es así entonces tengo que usar el CASE que dijiste como primera opción más ineficiente.

2 respuestas
AkA7

#5 Creo que estas intentando hacer esto:

SELECT
...bla bla bla
FROM bla bla bla
WHERE
    (customer.Email is null OR customer.Email = @Email) AND
    (customer.PostCode is null OR customer.PostCode = @PostCode) AND
    (customer.Name is null OR customer.Name= @Name) AND
    (customer.Surname is null OR customer.Surname= @Surname)

En tu query estas comprobando que el valor del parametro sea nulo, no el campo de la tabla.

1 respuesta
Czhincksx

#6 no porque eso me devolvería falsos positivos. Clientes que no tienen el campo con el mismo valor del parámetro pero lo tienen a null y da true.

Yo quería que si el parámetro era null no se comparara con el del cliente.

MTX_Anubis

#5 pues cambia '' por customer.Email: COALESCE(@Email, customer.Email)

Te han dado el 99% hecho...

1 respuesta
Czhincksx

#8 pues sí... Joer estoy espeso. Gracias!

JuAn4k4

Que BD es ?

En Oracle tienes execute inmediate: https://renenyffenegger.ch/notes/development/databases/Oracle/PL-SQL/execute-immediate/index
En sql server tienes EXECUTE sp_executesql N' https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql?view=sql-server-ver15
En mysql prepared statements: https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-prepared-statements.html

Depende de dónde quieras meterlos, tienes cosas que son más eficientes que los case/when

1 respuesta
Czhincksx

#10 Es MS SQL Server. No sé mucho más, no tengo control de la BD

1 respuesta
JuAn4k4

#11 No entiendo, ¿Quieres hacer un procedimiento almacenado pero no tienes control de la DB?
¿Seguro que no es una query dinámica desde tu aplicación?

1 respuesta
Czhincksx

#12 Es del cliente que tiene su tipo a cargo de la BD. La SP ya la tengo creada y puedo modificarla pero no sé mucho más, llevo tiempo sin tocar SQL XD

1 respuesta
JuAn4k4

#13 Exhale un vistazo https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql?view=sql-server-ver15

Consiste en crear el string con la query parametrizada y ejecutarla en el sp

1 1 respuesta
Czhincksx

#14 Vale gracias

Usuarios habituales

  • Czhincksx
  • JuAn4k4
  • MTX_Anubis
  • AkA7
  • Ranthas
  • Grise