2011-09-12 11 views
6

consideran este método simple:¿Cómo se pueden manejar los valores NULL y regulares sin utilizar diferentes declaraciones preparadas?

public ResultSet getByOwnerId(final Connection connection, final Integer id) throws SQLException { 
    PreparedStatement statement = connection.prepareStatement("SELECT * FROM MyTable WHERE MyColumn = ?"); 
    statement.setObject(1, id); 
    return statement.executeQuery(); 
} 

Se supone que el método de ejemplo para seleccionar todo, desde alguna mesa en la que iguale el valor de una columna, que deben ser simple. El feo detalle es que pasar NULL para el id resultará en un ResultSet vacío, sin importar cuántas filas haya en el DB porque SQL define NULL como no obligatorio, ni siquiera NULL. La única manera de seleccionar las filas que conozco es el uso de un diferente cláusula where:

SELECT * FROM MyTable WHERE MyColumn IS NULL 

Por desgracia, la única manera de hacer que el método funcione correctamente en todos los casos parece ser la de tener dos pathes de ejecución totalmente diferentes, uno para el caso donde el argumento id es nulo y uno para valores regulares.

Esto es muy feo y cuando tienes más de una columna que se puede anular puede ser muy complicado rápidamente. ¿Cómo se pueden manejar valores NULL y normales con la misma ruta/declaración de código?

+0

No consumo JDBC, pero en C# que generalmente configurar esta opción para que los '='/'SE null' seleccionados de forma dinámica?. El parámetro, si lo hay, sigue vinculado a través de la declaración preparada. –

+0

Si está utilizando SQL Server, puede hacer 'SET ANSI_NULLS OFF' y' field = NULL' funcionará. – NullUserException

+1

Considera Hibernate o JPA. Te salvará del estándar de JDBC. – BalusC

Respuesta

0

se puede utilizar una consulta como esta:

select * from MyTable where 
    case when ?1 is null then MyColumn is null else MyColumn = ?1 

Pero reutiliza el mismo parámetro, por lo que no sé si la sintaxis que he propuesto funcionará (1?).

2

No he probado esto, pero la manera de enviar a los nulos PreparedStatements es utilizar la opción setNull()

PreparedStatement statement = connection.prepareStatement("SELECT * FROM MyTable WHERE MyColumn = ?"); 
    if (id == null) 
     statement.setNull(1, java.sql.Types.INTEGER); 
    else  
     statement.setObject(1, id); 
    return statement.executeQuery(); 

EDITAR: Gracias por las respuestas @Gabe y @Vache. No parece que haya una manera fácil de hacer esto que no sea adoptar un enfoque más duradero para crear dinámicamente el estado preparado.

Algo como esto debería funcionar -

String sql = " SELECT * FROM MyTable WHERE " + (id==null)?"MyColumn is null":"MyColumn = ?" ; 
     PreparedStatement statement = connection.prepareStatement(sql); 
     if (id != null) 
      statement.setObject(1, id); 
     return statement.executeQuery(); 
+0

En ANSI SQL, 'MyColumn = NULL' nunca será verdadero, incluso cuando' MyColumn' tenga el valor 'NULL'. – Gabe

+0

Establecerá un "SQL nulo", pero el 'MyColumn = NULL' aún no devolverá resultados. 'setNull' se usa principalmente para consultas de inserción. – Vache

Cuestiones relacionadas