Cómo hacer que una columna de vista NO sea NULA

84

Estoy tratando de crear una vista en la que quiero que una columna sea solo verdadera o falsa. Sin embargo, parece que no importa lo que haga, SQL Server (2008) cree que mi columna de bits puede ser nula de alguna manera.

Tengo una tabla llamada "Producto" con la columna "Estado" que es INT, NULL. En una vista, quiero devolver una fila para cada fila en Producto, con una columna BIT establecida en verdadero si la columna Product.Status es igual a 3; de lo contrario, el campo de bits debería ser falso.

SQL de ejemplo

SELECT CAST( CASE ISNULL(Status, 0)  
               WHEN 3 THEN 1  
               ELSE 0  
             END AS bit) AS HasStatus  
FROM dbo.Product  

Si guardo esta consulta como una vista y miro las columnas en el Explorador de objetos, la columna HasStatus se establece en BIT, NULL. Pero nunca debería ser NULO. ¿Hay algún truco mágico de SQL que pueda usar para forzar que esta columna sea NOT NULL?

Tenga en cuenta que, si elimino el CAST()alrededor de CASE, la columna se establece correctamente como NOT NULL, pero luego el tipo de columna se establece en INT, que no es lo que quiero. Yo quiero que sea BIT. :-)

René
fuente

Respuestas:

150

Puede lograr lo que desea reorganizando un poco su consulta. El truco es que ISNULLtiene que estar en el exterior antes de que SQL Server entienda que el valor resultante nunca puede ser NULL.

SELECT ISNULL(CAST(
    CASE Status
        WHEN 3 THEN 1  
        ELSE 0  
    END AS bit), 0) AS HasStatus  
FROM dbo.Product  

Una de las razones por las que encuentro esto útil es cuando utilizo un ORM y no desea que el valor resultante se asigne a un tipo que acepta valores NULL. Puede facilitar las cosas en general si su aplicación considera que el valor nunca será nulo. Entonces no tiene que escribir código para manejar excepciones nulas, etc.

RedFilter
fuente
@Gunder: no te preocupes, en realidad es un poco arcano. Esto también es útil cuando se crea una columna de bits calculados en una tabla y se desea que el resultado no sea anulable.
RedFilter
8
Necesitaba algo similar, y descubrí que COALESCE()no funcionaba, en realidad tienes que usarloISNULL()
EvilBob22
@ EvilBob22 Eso es extraño, porque tanto COALESCE como ISNULL pueden devolver NULL. Solo una peculiaridad del compilador, supongo.
RedFilter
1
Esto, multiplicado por mil millones, para hacer que EntityFramework infiera una clave cuando normalmente no se inferiría una.
Erik
3

Para su información, para las personas que se encuentran con este mensaje, agregar el ISNULL () alrededor del exterior de la conversión / conversión puede estropear el optimizador en su vista.

Teníamos 2 tablas que usaban el mismo valor que una clave de índice pero con tipos de precisión numérica diferente (mala, lo sé) y nuestra vista se unía a ellas para producir el resultado final. Pero nuestro código de middleware buscaba un tipo de datos específico, y la vista tenía un CONVERT () alrededor de la columna devuelta

Noté, como lo hizo el OP, que los descriptores de columna del resultado de la vista lo definieron como anulable y estaba pensando que es una clave primaria / externa en 2 tablas; ¿Por qué querríamos que el resultado se definiera como anulable?

Encontré esta publicación, lancé ISNULL () alrededor de la columna y listo, ya no admite nulos.

El problema fue que el rendimiento de la vista se fue directamente al inodoro cuando se filtró una consulta en esa columna.

Por alguna razón, un CONVERT () explícito en la columna de resultados de la vista no arruinó el optimizador (iba a tener que hacerlo de todos modos debido a las diferentes precisiones) pero agregar un contenedor ISNULL () redundante sí lo hizo, en un gran camino.

usuario1664043
fuente
¿Podría mostrar la solución sobre cómo garantizar / indicar la no nulabilidad con CONVERT()un ejemplo, por favor?
OR Mapper
1
Hola O, lo siento, no vi esto por un tiempo. He aquí un ejemplo. Si tiene CONVERT (BIT, U.RETIRED), 0) AS Retired en su vista, convirtiendo un byte o una columna int en un bit / bool, entonces se convierte en anulable. Puede hacer que esa columna en su vista no acepte nulos reemplazándola con ISNULL (CONVERT (BIT, U.RETIRED), 0) AS Retired. Si U.RETIRED no fue nulo para comenzar, funcionalmente no cambia nada excepto la columna en la vista. ADVERTENCIA: ISNULL () puede interferir con la optimización de consultas y la elección de índices.
user1664043
-3

Todo lo que puede hacer en una instrucción Select es controlar los datos que el motor de la base de datos le envía como cliente. La instrucción select no tiene ningún efecto sobre la estructura de la tabla subyacente. Para modificar la estructura de la tabla, debe ejecutar una instrucción Alter Table.

  1. Primero asegúrese de que actualmente no haya nulos en ese campo de bits en la tabla
  2. Luego ejecute la siguiente instrucción ddl: Alter Table dbo.Product Alter column status bit not null

Si, otoh, todo lo que está tratando de hacer es controlar la salida de la vista, entonces lo que está haciendo es suficiente. Su sintaxis garantizará que la salida de la columna HasStatus en el conjunto de resultados de las vistas nunca será nula. Será siempre ser o valor de bit = 1 o el valor de bit = 0. No se preocupe lo que dice el explorador de objetos ...

Charles Bretana
fuente
6
No quiero cambiar la columna de la tabla. La columna se define como una columna de entero, que permite nulos. Esto se ajusta a nuestras especificaciones. Pero necesito una vista que devuelva una columna con un campo de bits, que no puede ser nulo. No es suficiente que sepa que no puede ser nulo, la columna tiene que ser NO NULO, para que se mapee correctamente en nuestro ORM.
René