En SQL , nulo o NULL es un marcador especial que se utiliza para indicar que un valor de datos no existe en la base de datos . Introducido por el creador del modelo de base de datos relacional , E. F. Codd , SQL null sirve para cumplir con el requisito de que todos los verdaderos sistemas de gestión de bases de datos relacionales ( RDBMS ) admitan una representación de "información faltante e información inaplicable". Codd también introdujo el uso del símbolo griego omega (ω) en minúsculas para representar nulo en la teoría de bases de datos . En SQL, NULL
es una palabra reservada que se utiliza para identificar este marcador.
Un valor nulo no debe confundirse con un valor de . Un valor nulo indica la falta de un valor, que no es lo mismo que un valor cero. Por ejemplo, considere la pregunta "¿Cuántos libros posee Adam?" La respuesta puede ser "cero" (sabemos que no posee ninguno ) o "nula" ( no sabemos cuántos posee). En una tabla de base de datos, la columna que informa esta respuesta comenzaría sin valor (marcada como nulo) y no se actualizaría con el valor cero hasta que se determine que Adam no posee libros.
En SQL, nulo es un marcador, no un valor. Este uso es bastante diferente de la mayoría de los lenguajes de programación, donde un valor nulo de una referencia significa que no apunta a ningún objeto .
EF Codd mencionó los nulos como método para representar datos faltantes en el modelo relacional en un artículo de 1975 en el FDT Bulletin de ACM - SIGMOD . El artículo de Codd que se cita más comúnmente en relación con la semántica de Null (tal como se adoptó en SQL) es su artículo de 1979 en ACM Transactions on Database Systems , en el que también presentó su Relational Model/Tasmania , aunque muchas de las otras propuestas de este último artículo ha permanecido oscuro. La sección 2.3 de su artículo de 1979 detalla la semántica de la propagación de nulos en operaciones aritméticas, así como comparaciones que emplean una lógica ternaria (de tres valores) al comparar con nulos; también detalla el tratamiento de los nulos en otras operaciones de conjuntos (este último tema sigue siendo controvertido hoy en día). En los círculos de teoría de bases de datos , la propuesta original de Codd (1975, 1979) ahora se conoce como "tablas de Codd". [1] Codd luego reforzó su requisito de que todos los RDBMS admitan Null para indicar datos faltantes en un artículo de dos partes de 1985 publicado en la revista Computerworld . [2] [3]
El estándar SQL de 1986 adoptó básicamente la propuesta de Codd después de un prototipo de implementación en IBM System R. Aunque Don Chamberlin reconoció los nulos (junto con las filas duplicadas) como una de las características más controvertidas de SQL, defendió el diseño de Nulls en SQL invocando argumentos pragmáticos de que era la forma menos costosa de soporte del sistema para la información faltante, salvando al programador de muchas comprobaciones duplicadas a nivel de aplicación (consulte problema de semipredicado ) y al mismo tiempo proporciona al diseñador de la base de datos la opción de no utilizar valores nulos si así lo desea; por ejemplo, para evitar anomalías bien conocidas (discutidas en la sección de semántica de este artículo). Chamberlin también argumentó que además de proporcionar algunas funciones de valor faltante, la experiencia práctica con Nulls también condujo a otras características del lenguaje que dependen de Nulls, como ciertas construcciones de agrupación y uniones externas. Finalmente, argumentó que en la práctica los valores nulos también terminan usándose como una forma rápida de parchar un esquema existente cuando necesita evolucionar más allá de su intención original, codificando no para información faltante sino más bien para información inaplicable; por ejemplo, una base de datos que rápidamente necesita admitir automóviles eléctricos y al mismo tiempo tener una columna de millas por galón. [4]
Codd indicó en su libro de 1990 The Relational Model for Database Management, Version 2 que el único Null exigido por el estándar SQL era inadecuado y debería ser reemplazado por dos marcadores de tipo Null separados para indicar el motivo por el cual faltan datos. En el libro de Codd, estos dos marcadores de tipo nulo se denominan "valores A" y "valores I", que representan "faltantes pero aplicables" y "faltantes pero inaplicables", respectivamente. [5] La recomendación de Codd habría requerido que el sistema lógico de SQL se ampliara para dar cabida a un sistema lógico de cuatro valores. Debido a esta complejidad adicional, la idea de múltiples Nulls con diferentes definiciones no ha ganado una aceptación generalizada en el dominio de los profesionales de bases de datos. Sin embargo, sigue siendo un campo de investigación activo y aún se publican numerosos artículos.
Null ha sido foco de controversia y fuente de debate debido a su lógica de tres valores asociada (3VL), requisitos especiales para su uso en uniones SQL y el manejo especial requerido por funciones agregadas y operadores de agrupación SQL. El profesor de informática Ron van der Meyden resumió los distintos problemas de la siguiente manera: "Las inconsistencias en el estándar SQL significan que no es posible atribuir ninguna semántica lógica intuitiva al tratamiento de nulos en SQL". [1] Aunque se han hecho varias propuestas para resolver estos problemas, la complejidad de las alternativas ha impedido su adopción generalizada.
Debido a que Null no es un valor de datos, sino un marcador de un valor ausente, el uso de operadores matemáticos en Null da un resultado desconocido, que está representado por Null. [6] En el siguiente ejemplo, multiplicar 10 por Nulo da como resultado Nulo:
10 * NULL - El resultado es NULL
Esto puede conducir a resultados inesperados. Por ejemplo, cuando se intenta dividir Null entre cero, las plataformas pueden devolver Null en lugar de generar una "excepción de datos: división por cero" esperada. [6] Aunque este comportamiento no está definido por el estándar ISO SQL, muchos proveedores de DBMS tratan esta operación de manera similar. Por ejemplo, las plataformas Oracle, PostgreSQL, MySQL Server y Microsoft SQL Server devuelven un resultado nulo para lo siguiente:
NULO / 0
Las operaciones de concatenación de cadenas , que son comunes en SQL, también dan como resultado Nulo cuando uno de los operandos es Nulo. [7] El siguiente ejemplo demuestra el resultado nulo devuelto al utilizar Null con el ||
operador de concatenación de cadenas SQL.
'Pescado' || NULO || 'Chips' : el resultado es NULO
Esto no es cierto para todas las implementaciones de bases de datos. En un RDBMS de Oracle, por ejemplo, NULL y la cadena vacía se consideran lo mismo y, por lo tanto, 'Fish' || NULO || 'Chips' da como resultado 'Chips de pescado'. [8]
Dado que Null no es miembro de ningún dominio de datos , no se considera un "valor", sino más bien un marcador (o marcador de posición) que indica el valor indefinido . Debido a esto, las comparaciones con Null nunca pueden dar como resultado Verdadero o Falso, sino siempre un tercer resultado lógico, Desconocido. [9] El resultado lógico de la siguiente expresión, que compara el valor 10 con Nulo, es Desconocido:
SELECT 10 = NULL - Resultados desconocidos
Sin embargo, ciertas operaciones en Null pueden devolver valores si el valor ausente no es relevante para el resultado de la operación. Considere el siguiente ejemplo:
SELECCIONAR NULO O VERDADERO - Resultados en Verdadero
En este caso, el hecho de que el valor a la izquierda de OR sea incognoscible es irrelevante, porque el resultado de la operación OR sería Verdadero independientemente del valor a la izquierda.
SQL implementa tres resultados lógicos, por lo que las implementaciones de SQL deben proporcionar una lógica especializada de tres valores (3VL) . Las reglas que gobiernan la lógica de tres valores de SQL se muestran en las tablas siguientes ( p y q representan estados lógicos)" [10] Las tablas de verdad que SQL utiliza para AND, OR y NOT corresponden a un fragmento común de los tres valores de Kleene y Łukasiewicz. lógica valorada (que difieren en su definición de implicación, sin embargo, SQL no define tal operación [11] ).
La lógica de tres valores de SQL se encuentra en el lenguaje de manipulación de datos (DML) al comparar predicados de declaraciones y consultas DML. La WHERE
cláusula hace que la instrucción DML actúe sólo en aquellas filas para las cuales el predicado se evalúa como Verdadero. Las filas para las cuales el predicado se evalúa como Falso o Desconocido no se ven afectadas por declaraciones INSERT
, UPDATE
o DELETE
DML y las consultas las descartan SELECT
. Interpretar Desconocido y Falso como el mismo resultado lógico es un error común que se encuentra al tratar con Nulos. [10] El siguiente ejemplo sencillo demuestra esta falacia:
SELECCIONE * DESDE t DONDE i = NULL ;
La consulta de ejemplo anterior lógicamente siempre devuelve cero filas porque la comparación de la columna i con Null siempre devuelve Desconocido, incluso para aquellas filas donde i es Null. El resultado Desconocido hace que la SELECT
declaración descarte sumariamente todas y cada una de las filas. (Sin embargo, en la práctica, algunas herramientas SQL recuperarán filas mediante una comparación con Null).
Los operadores de comparación de SQL básicos siempre devuelven Desconocido cuando se compara algo con Null, por lo que el estándar SQL proporciona dos predicados de comparación especiales específicos de Null. Los predicados IS NULL
y (que utilizan una sintaxis de sufijo ) prueban si los datos son nulos o no. [12]IS NOT NULL
El estándar SQL contiene la característica opcional F571 "Pruebas de valor de verdad" que introduce tres operadores unarios lógicos adicionales (seis de hecho, si contamos su negación, que forma parte de su sintaxis), utilizando también notación postfija. Tienen las siguientes tablas de verdad: [13]
La característica F571 es ortogonal a la presencia del tipo de datos booleano en SQL (que se analiza más adelante en este artículo) y, a pesar de las similitudes sintácticas, F571 no introduce literales booleanos o de tres valores en el lenguaje. La característica F571 estaba presente en SQL92 , [14] mucho antes de que se introdujera el tipo de datos booleano en el estándar en 1999. Sin embargo, la característica F571 se implementa en pocos sistemas; PostgreSQL es uno de los que lo implementa.
La adición de ES DESCONOCIDO a los otros operadores de la lógica de tres valores de SQL hace que la lógica de tres valores de SQL sea funcionalmente completa , [15] lo que significa que sus operadores lógicos pueden expresar (en combinación) cualquier función lógica de tres valores concebible.
En sistemas que no admiten la característica F571, es posible emular IS UNKNOWN p repasando cada argumento que podría hacer que la expresión p sea Desconocida y probar esos argumentos con IS NULL u otras funciones específicas de NULL, aunque esto puede ser más incómodo.
En la lógica de tres valores de SQL, la ley del medio excluido , p O NO p , ya no se evalúa como verdadera para todo p . Más precisamente, en la lógica de tres valores de SQL p O NO p se desconoce precisamente cuando p es desconocido y verdadero en caso contrario. Debido a que las comparaciones directas con Null dan como resultado un valor lógico desconocido, la siguiente consulta
SELECCIONE * DE cosas DONDE ( x = 10 ) O NO ( x = 10 );
no es equivalente en SQL con
SELECCIONAR * DE cosas ;
si la columna x contiene nulos; en ese caso, la segunda consulta devolvería algunas filas que la primera no devuelve, es decir, todas aquellas en las que x es nulo. En la lógica clásica de dos valores, la ley del tercero excluido permitiría la simplificación del predicado de la cláusula WHERE, de hecho su eliminación. Intentar aplicar la ley del tercero excluido al 3VL de SQL es efectivamente una falsa dicotomía . La segunda consulta es en realidad equivalente a:
SELECCIONAR * DE cosas ; - es (debido a 3VL) equivalente a: SELECCIONAR * DE cosas DONDE ( x = 10 ) O NO ( x = 10 ) O x ES NULL ;
Por lo tanto, para simplificar correctamente la primera declaración en SQL es necesario devolver todas las filas en las que x no es nulo.
SELECCIONE * DE cosas DONDE x NO ES NULO ;
En vista de lo anterior, observe que para la cláusula WHERE de SQL se puede escribir una tautología similar a la ley del tercero excluido. Suponiendo que el operador ES DESCONOCIDO está presente, p OR (NO p ) O ( p ES DESCONOCIDO) es verdadero para cada predicado p . Entre los lógicos, esto se llama ley de la cuarta excluida .
Hay algunas expresiones SQL en las que es menos obvio dónde ocurre el falso dilema, por ejemplo:
SELECCIONE 'ok' DONDE 1 NO EN ( SELECCIONE CAST ( NULL COMO INTEGER )) UNION SELECCIONE 'ok' DONDE 1 EN ( SELECCIONE CAST ( NULL COMO INTEGER ));
no produce filas porque IN
se traduce en una versión iterada de igualdad sobre el conjunto de argumentos y 1<>NULL es Desconocido, al igual que 1=NULL es Desconocido. (El CAST en este ejemplo solo es necesario en algunas implementaciones de SQL como PostgreSQL, que de lo contrario lo rechazaría con un error de verificación de tipo. En muchos sistemas, SELECT NULL simple funciona en la subconsulta). El caso anterior que falta es, por supuesto:
SELECCIONE 'ok' DONDE ( 1 EN ( SELECCIONE CAST ( NULL AS INTEGER ))) ES DESCONOCIDO ;
Las uniones se evalúan utilizando las mismas reglas de comparación que para las cláusulas WHERE. Por lo tanto, se debe tener cuidado al utilizar columnas que aceptan valores NULL en los criterios de unión de SQL. En particular, una tabla que contiene valores nulos no es igual a una autounión natural de sí misma, lo que significa que, si bien es cierto para cualquier relación R en álgebra relacional , una autounión SQL excluirá todas las filas que tengan un nulo en cualquier lugar. [16] Un ejemplo de este comportamiento se da en la sección que analiza la semántica de valores perdidos de Nulls.
La COALESCE
función o CASE
expresiones SQL se pueden utilizar para "simular" la igualdad nula en los criterios de unión, y los predicados IS NULL
y IS NOT NULL
también se pueden utilizar en los criterios de unión. El siguiente predicado prueba la igualdad de los valores A y B y trata los nulos como iguales.
( A = B ) O ( A ES NULO Y B ES NULO )
SQL proporciona dos tipos de expresiones condicionales . Uno se llama "CASO simple" y funciona como una declaración de cambio . El otro se denomina "CASO buscado" en el estándar y funciona como if...elseif .
Las expresiones simples CASE
utilizan comparaciones de igualdad implícitas que operan bajo las mismas reglas que las WHERE
reglas de la cláusula DML para Null. Por lo tanto, una expresión simpleCASE
no puede verificar directamente la existencia de Null. Una comprobación de Nulo en una CASE
expresión simple siempre da como resultado Desconocido, como en el siguiente:
SELECCIONE CASO i CUANDO NULL ENTONCES 'Es nulo' - Esto nunca se devolverá CUANDO 0 ENTONCES 'Es cero' - Esto se devolverá cuando i = 0 CUANDO 1 ENTONCES 'Es uno' - Esto se devolverá cuando i = 1 FINAL DE t ;
Debido a que la expresión i = NULL
se evalúa como Desconocida sin importar el valor que contenga la columna i (incluso si contiene Nulo), la cadena 'Is Null'
nunca se devolverá.
Por otro lado, una CASE
expresión "buscada" puede utilizar predicados como IS NULL
y IS NOT NULL
en sus condiciones. El siguiente ejemplo muestra cómo utilizar una CASE
expresión buscada para comprobar correctamente si hay valores nulos:
SELECCIONE CASO CUANDO i ES NULO ENTONCES ' Resultado nulo' - Esto se devolverá cuando i sea NULO CUANDO i = 0 ENTONCES 'Cero' - Esto se devolverá cuando i = 0 CUANDO i = 1 ENTONCES 'Uno' - Esto será devuelto cuando i = 1 FINAL DE t ;
En la CASE
expresión buscada, 'Null Result'
se devuelve la cadena para todas las filas en las que i es nulo.
El dialecto SQL de Oracle proporciona una función incorporada DECODE
que se puede utilizar en lugar de las expresiones CASE simples y considera dos nulos iguales.
SELECCIONE DECODIFICAR ( i , NULL , 'Resultado nulo' , 0 , 'Cero' , 1 , 'Uno' ) FROM t ;
Finalmente, todas estas construcciones devuelven un valor NULL si no se encuentra ninguna coincidencia; Tienen una ELSE NULL
cláusula de incumplimiento.
SQL/PSM (Módulos almacenados persistentes de SQL) define extensiones de procedimiento para SQL, como la IF
declaración. Sin embargo, los principales proveedores de SQL históricamente han incluido sus propias extensiones de procedimientos patentadas. Las extensiones de procedimiento para bucles y comparaciones operan bajo reglas de comparación nulas similares a las de las declaraciones y consultas DML. El siguiente fragmento de código, en formato estándar ISO SQL, demuestra el uso de Null 3VL en una IF
declaración.
SI i = NULL ENTONCES SELECCIONE 'El resultado es verdadero' ELSEIF NOT ( i = NULL ) ENTONCES SELECCIONE 'El resultado es falso' ELSE SELECCIONE 'El resultado es desconocido' ;
La IF
declaración realiza acciones sólo para aquellas comparaciones que se evalúan como Verdaderas. Para declaraciones que se evalúan como Falso o Desconocido, la IF
declaración pasa el control a la ELSEIF
cláusula y, finalmente, a la ELSE
cláusula. El resultado del código anterior siempre será el mensaje 'Result is Unknown'
ya que las comparaciones con Null siempre se evalúan como Desconocido.
El trabajo innovador de T. Imieliński y W. Lipski Jr. (1984) [17] proporcionó un marco en el que evaluar la semántica prevista de varias propuestas para implementar la semántica de valores perdidos, conocida como álgebras de Imieliński-Lipski . Esta sección sigue aproximadamente el capítulo 19 del libro de texto "Alice". [18] Una presentación similar aparece en la reseña de Ron van der Meyden, §10.4. [1]
Las construcciones que representan información faltante, como las tablas Codd, en realidad pretenden representar un conjunto de relaciones, una para cada posible instanciación de sus parámetros; en el caso de las tablas Codd, esto significa reemplazar los nulos con algún valor concreto. Por ejemplo,
Se dice que un constructo (como una tabla de Codd) es un sistema de representación fuerte (de información faltante) si cualquier respuesta a una consulta realizada sobre el constructo puede particularizarse para obtener una respuesta para cualquier consulta correspondiente sobre las relaciones que representa, lo cual son vistos como modelos del constructo. Más precisamente, si q es una fórmula de consulta en el álgebra relacional (de relaciones "puras") y si q es su elevación a una construcción destinada a representar información faltante, una representación fuerte tiene la propiedad de que para cualquier consulta q y (tabla) constructo T , q levanta todas las respuestas al constructo, es decir:
(Lo anterior tiene que ser válido para consultas que toman cualquier número de tablas como argumentos, pero la restricción a una tabla es suficiente para esta discusión). Claramente, las tablas Codd no tienen esta fuerte propiedad si las selecciones y proyecciones se consideran parte del lenguaje de consulta. Por ejemplo, todas las respuestas a
SELECCIONE * DESDE Emp DONDE Edad = 22 ;
debería incluir la posibilidad de que pueda existir una relación como EmpH22. Sin embargo, las tablas Codd no pueden representar la disyunción "resultado posiblemente con 0 o 1 filas". Sin embargo, un dispositivo, principalmente de interés teórico, llamado tabla condicional (o tabla c) puede representar tal respuesta:
donde la columna de condición se interpreta como que la fila no existe si la condición es falsa. Resulta que debido a que las fórmulas en la columna de condiciones de una tabla c pueden ser fórmulas lógicas proposicionales arbitrarias , un algoritmo para el problema de si una tabla c representa alguna relación concreta tiene una complejidad co-NP-completa , por lo que es de poca importancia. valor práctico.
Por tanto, es deseable una noción más débil de representación. Imielinski y Lipski introdujeron la noción de representación débil , que esencialmente permite que las consultas (elevadas) sobre una construcción devuelvan una representación solo para información segura , es decir, si es válida para todas las instancias (modelos) del " mundo posible " de la construcción. Concretamente, un constructo es un sistema de representación débil si
El lado derecho de la ecuación anterior es la información segura , es decir, información que ciertamente se puede extraer de la base de datos independientemente de qué valores se utilicen para reemplazar los valores nulos en la base de datos. En el ejemplo que consideramos anteriormente, es fácil ver que la intersección de todos los modelos posibles (es decir, la información segura) de la selección de consulta está en realidad vacía porque, por ejemplo, la consulta (sin levantar) no devuelve filas para la relación EmpH37. De manera más general, Imielinski y Lipski demostraron que las tablas de Codd son un sistema de representación débil si el lenguaje de consulta se restringe a proyecciones, selecciones (y cambio de nombre de columnas). Sin embargo, tan pronto como agregamos uniones o uniones al lenguaje de consulta, incluso esta propiedad débil se pierde, como se evidencia en la siguiente sección.WHERE Age = 22
Considere la siguiente consulta sobre la misma tabla Codd Emp de la sección anterior:
SELECCIONE Nombre DE Emp DONDE Edad = 22 UNION SELECCIONE Nombre DE Emp DONDE Edad <> 22 ;
Cualquiera que sea el valor concreto que uno elija para la NULL
edad de Harriet, la consulta anterior devolverá la columna completa de nombres de cualquier modelo de Emp , pero cuando la consulta (elevada) se ejecuta en el propio Emp , Harriet siempre faltará, es decir, tenemos :
Por lo tanto, cuando se agregan uniones al lenguaje de consulta, las tablas Codd ni siquiera son un sistema de representación débil de información faltante, lo que significa que las consultas sobre ellas ni siquiera reportan toda la información segura . Es importante señalar aquí que la semántica de UNION en Nulls, que se analiza en una sección posterior, ni siquiera entró en juego en esta consulta. La naturaleza "olvidadiza" de las dos subconsultas fue todo lo que se necesitó para garantizar que cierta información segura no se reportara cuando se ejecutó la consulta anterior en la tabla Codd Emp.
Para las uniones naturales , el ejemplo necesario para mostrar que alguna consulta puede no informar cierta información es un poco más complicado. Considere la mesa
y la consulta
SELECCIONE F1 , F3 DESDE ( SELECCIONE F1 , F2 DESDE J ) COMO F12 UNIÓN NATURAL ( SELECCIONE F2 , F3 DESDE J ) COMO F23 ;
La intuición de lo que sucede arriba es que las tablas Codd que representan las proyecciones en las subconsultas pierden de vista el hecho de que los Nulos en las columnas F12.F2 y F23.F2 son en realidad copias de los originales en la tabla J. Esta observación sugiere que una mejora relativamente simple de las tablas Codd (que funciona correctamente para este ejemplo) sería usar constantes de Skolem (es decir, funciones de Skolem que también son funciones constantes ), digamos ω 12 y ω 22 en lugar de un solo símbolo NULL. Este enfoque, llamado tablas v o tablas Naive, es computacionalmente menos costoso que las tablas c analizadas anteriormente. Sin embargo, todavía no es una solución completa para información incompleta en el sentido de que las tablas v son solo una representación débil para consultas que no usan negaciones en la selección (y tampoco usan ninguna diferencia de conjuntos). El primer ejemplo considerado en esta sección es el uso de una cláusula de selección negativa, por lo que también es un ejemplo en el que las consultas de v-tables no reportarían información segura.WHERE Age <> 22
El lugar principal en el que la lógica de tres valores de SQL se cruza con el lenguaje de definición de datos (DDL) de SQL es en forma de restricciones de verificación . Una restricción de verificación colocada en una columna opera bajo un conjunto de reglas ligeramente diferente al de la WHERE
cláusula DML. Mientras que una cláusula DML WHERE
debe evaluarse como Verdadera para una fila, una restricción de verificación no debe evaluarse como Falso. (Desde una perspectiva lógica, los valores designados son Verdadero y Desconocido). Esto significa que una restricción de verificación tendrá éxito si el resultado de la verificación es Verdadero o Desconocido. La siguiente tabla de ejemplo con una restricción de verificación prohibirá que se inserten valores enteros en la columna i , pero permitirá que se inserte Null ya que el resultado de la verificación siempre se evaluará como Desconocido para Nulls. [19]
CREAR TABLA t ( i INTEGER , RESTRICCIÓN ck_i CHECK ( i < 0 Y i = 0 Y i > 0 ) );
Debido al cambio en los valores designados en relación con la cláusula WHERE , desde una perspectiva lógica, la ley del tercero excluido es una tautología para las restricciones CHECK , el significado siempre tiene éxito. Además, suponiendo que los valores nulos deben interpretarse como valores existentes pero desconocidos, algunos CHECK patológicos como el anterior permiten la inserción de valores nulos que nunca podrían ser reemplazados por ningún valor que no sea nulo.CHECK (p OR NOT p)
Para restringir una columna para que rechace nulos, NOT NULL
se puede aplicar la restricción, como se muestra en el siguiente ejemplo. La NOT NULL
restricción es semánticamente equivalente a una restricción de verificación con un IS NOT NULL
predicado.
CREAR TABLA t ( i INTEGER NOT NULL );
De forma predeterminada, las restricciones de verificación de claves externas tienen éxito si alguno de los campos de dichas claves es nulo. Por ejemplo, la mesa
CREAR TABLA Libros ( título VARCHAR ( 100 ), autor_último VARCHAR ( 20 ), autor_primero VARCHAR ( 20 ), CLAVE EXTRANJERA ( autor_último , autor_primero ) REFERENCIAS Autores ( apellido , nombre ));
permitiría la inserción de filas donde autor_último o autor_primero son NULL
independientemente de cómo se define la tabla Autores o lo que contiene. Más precisamente, un valor nulo en cualquiera de estos campos permitiría cualquier valor en el otro, incluso si no se encuentra en la tabla de Autores. Por ejemplo, si los Autores solo contuvieran ('Doe', 'John')
, entonces ('Smith', NULL)
se cumpliría la restricción de clave externa. SQL-92 agregó dos opciones adicionales para limitar las coincidencias en tales casos. Si MATCH PARTIAL
se agrega después de la REFERENCES
declaración, cualquier valor no nulo debe coincidir con la clave externa; por ejemplo, ('Doe', NULL)
aún coincidiría, pero ('Smith', NULL)
no. Finalmente, si MATCH FULL
se agrega, ('Smith', NULL)
tampoco coincidiría con la restricción, pero (NULL, NULL)
aún así la coincidiría.
NULL
Las uniones externas de SQL , incluidas las uniones externas izquierdas, las uniones externas derechas y las uniones externas completas, producen automáticamente valores nulos como marcadores de posición para los valores faltantes en tablas relacionadas. Para las uniones exteriores izquierdas, por ejemplo, se generan valores nulos en lugar de las filas que faltan en la tabla que aparece en el lado derecho del LEFT OUTER JOIN
operador. El siguiente ejemplo sencillo utiliza dos tablas para demostrar la producción de marcadores de posición nulos en una unión exterior izquierda.
La primera tabla ( Empleado ) contiene números de identificación de empleados y nombres, mientras que la segunda tabla ( Número de teléfono ) contiene números de identificación de empleados y números de teléfono relacionados , como se muestra a continuación.
La siguiente consulta SQL de ejemplo realiza una combinación externa izquierda en estas dos tablas.
SELECCIONAR e . DNI , e.g. Apellido , e . Nombre , pág . Número DEL Empleado e IZQUIERDO UNIÓN EXTERNA Número de teléfono pn ON e . ID = pn . IDENTIFICACIÓN ;
El conjunto de resultados generado por esta consulta demuestra cómo SQL usa Null como marcador de posición para los valores que faltan en la tabla de la derecha ( PhoneNumber ), como se muestra a continuación.
SQL define funciones agregadas para simplificar los cálculos agregados de datos del lado del servidor. Excepto la COUNT(*)
función, todas las funciones agregadas realizan un paso de eliminación de nulos, de modo que los nulos no se incluyen en el resultado final del cálculo. [20]
Tenga en cuenta que eliminar Null no equivale a reemplazar Null con cero. Por ejemplo, en la siguiente tabla, AVG(i)
(el promedio de los valores de i
) dará un resultado diferente al de AVG(j)
:
Aquí AVG(i)
es 200 (el promedio de 150, 200 y 250), mientras que AVG(j)
es 150 (el promedio de 150, 200, 250 y 0). Un efecto secundario bien conocido de esto es que en SQL AVG(z)
es equivalente a no SUM(z)/COUNT(*)
pero SUM(z)/COUNT(z)
. [4]
La salida de una función agregada también puede ser nula. Aquí hay un ejemplo:
SELECCIONE RECUENTO ( * ), MIN ( e . Salario ), MAX ( e . Salario ) DESDE Empleado e DONDE e . Apellido COMO '%Jones%' ;
Esta consulta siempre generará exactamente una fila, contando la cantidad de empleados cuyo apellido contiene "Jones" y brindando el salario mínimo y máximo encontrado para esos empleados. Sin embargo, ¿qué sucede si ninguno de los empleados cumple con los criterios dados? Calcular el valor mínimo o máximo de un conjunto vacío es imposible, por lo que esos resultados deben ser NULL, lo que indica que no hay respuesta. Este no es un valor desconocido, es un valor nulo que representa la ausencia de un valor. El resultado sería:
Debido a que SQL:2003 define todos los marcadores nulos como desiguales entre sí, se requirió una definición especial para agrupar los nulos al realizar ciertas operaciones. SQL define "dos valores cualesquiera que sean iguales entre sí, o dos valores nulos cualesquiera", como "no distintos". [21] Esta definición de no distinto permite a SQL agrupar y ordenar valores nulos cuando GROUP BY
se utiliza la cláusula (y otras palabras clave que realizan la agrupación).
Otras operaciones, cláusulas y palabras clave de SQL utilizan "no distintos" en el tratamiento de los valores nulos. Estos incluyen lo siguiente:
PARTITION BY
cláusula de clasificación y funciones de ventanas comoROW_NUMBER
UNION
, INTERSECT
y EXCEPT
operador, que tratan los NULL como iguales para fines de comparación/eliminación de filasDISTINCT
palabra clave utilizada en SELECT
consultasEl principio de que los nulos no son iguales entre sí (sino que el resultado es desconocido) se viola efectivamente en la especificación SQL para el UNION
operador, que identifica los nulos entre sí. [1] En consecuencia, algunas operaciones de conjuntos en SQL, como unión o diferencia, pueden producir resultados que no representan información segura, a diferencia de las operaciones que involucran comparaciones explícitas con NULL (por ejemplo, aquellas en una WHERE
cláusula discutida anteriormente). En la propuesta de Codd de 1979 (que fue básicamente adoptada por SQL92), esta inconsistencia semántica se racionaliza argumentando que la eliminación de duplicados en operaciones de conjuntos ocurre "a un nivel de detalle más bajo que las pruebas de igualdad en la evaluación de operaciones de recuperación". [11]
El estándar SQL no define explícitamente un orden de clasificación predeterminado para los valores nulos. En cambio, en sistemas conformes, los nulos se pueden ordenar antes o después de todos los valores de datos utilizando las cláusulas NULLS FIRST
o NULLS LAST
de la ORDER BY
lista, respectivamente. Sin embargo, no todos los proveedores de DBMS implementan esta funcionalidad. Los proveedores que no implementen esta funcionalidad pueden especificar tratamientos diferentes para la clasificación de valores nulos en el DBMS. [19]
Algunos productos SQL no indexan claves que contienen valores NULL. Por ejemplo, las versiones de PostgreSQL anteriores a la 8.3 no lo hacían, y la documentación para un índice de árbol B indicaba que [22]
Los árboles B pueden manejar consultas de igualdad y rango sobre datos que se pueden clasificar en algún orden. En particular, el planificador de consultas de PostgreSQL considerará el uso de un índice de árbol B siempre que una columna indexada esté involucrada en una comparación usando uno de estos operadores: < ≤ = ≥ >
Las construcciones equivalentes a combinaciones de estos operadores, como BETWEEN e IN, también se pueden implementar con una búsqueda de índice de árbol B. (Pero tenga en cuenta que IS NULL no es equivalente a = y no es indexable).
En los casos en los que el índice exige la unicidad, los NULL se excluyen del índice y no se exige la unicidad entre los NULL. Nuevamente, citando la documentación de PostgreSQL : [23]
Cuando un índice se declara único, no se permitirán varias filas de la tabla con valores indexados iguales. Los nulos no se consideran iguales. Un índice único de varias columnas solo rechazará los casos en los que todas las columnas indexadas sean iguales en dos filas.
Esto es coherente con el comportamiento definido por SQL:2003 de las comparaciones nulas escalares.
Otro método de indexación de valores nulos implica manejarlos como no distintos de acuerdo con el comportamiento definido en SQL:2003. Por ejemplo, la documentación de Microsoft SQL Server establece lo siguiente: [24]
Para fines de indexación, los NULL se comparan como iguales. Por lo tanto, no se puede crear un índice único, o restricción UNIQUE, si las claves son NULL en más de una fila. Seleccione columnas que estén definidas como NOT NULL cuando se elijan columnas para un índice único o una restricción única.
Ambas estrategias de indexación son consistentes con el comportamiento de Nulls definido en SQL:2003. Debido a que las metodologías de indexación no están definidas explícitamente en el estándar SQL:2003, las estrategias de indexación para Nulls quedan enteramente en manos de los proveedores para diseñarlas e implementarlas.
SQL define dos funciones para manejar explícitamente nulos: NULLIF
y COALESCE
. Ambas funciones son abreviaturas de expresiones buscadasCASE
. [25]
La NULLIF
función acepta dos parámetros. Si el primer parámetro es igual al segundo parámetro, NULLIF
devuelve Nulo. De lo contrario, se devuelve el valor del primer parámetro.
NULLIF ( valor1 , valor2 )
Por tanto, NULLIF
es una abreviatura de la siguiente CASE
expresión:
CASO CUANDO valor1 = valor2 ENTONCES NULL ELSE valor1 FINAL
La COALESCE
función acepta una lista de parámetros y devuelve el primer valor no nulo de la lista:
FUSIONAR ( valor1 , valor2 , valor3 , ...)
COALESCE
se define como una abreviatura de la siguiente CASE
expresión SQL:
CASO CUANDO el valor1 NO ES NULO ENTONCES valor1 CUANDO el valor2 NO ES NULO ENTONCES valor2 CUANDO el valor3 NO ES NULO ENTONCES valor3 ... FINAL
Algunos DBMS SQL implementan funciones específicas del proveedor similares a COALESCE
. Algunos sistemas (por ejemplo, Transact-SQL ) implementan una ISNULL
función u otras funciones similares que son funcionalmente similares a COALESCE
. (Consulte Is
funciones para obtener más información sobre las IS
funciones en Transact-SQL).
La NVL
función de Oracle acepta dos parámetros. Devuelve el primer parámetro no NULL o NULL si todos los parámetros son NULL.
Una COALESCE
expresión se puede convertir en una NVL
expresión equivalente así:
UNIRSE ( val1 , ... , val { n } )
se convierte en:
NVL ( val1 , NVL ( val2 , NVL ( val3 , … , NVL ( val { n - 1 } , val { n } ) … )))
Un caso de uso de esta función es reemplazar en una expresión un NULL por un valor como NVL(SALARY, 0)
el que dice, "si SALARY
es NULL, reemplácelo con el valor 0".
Sin embargo, hay una excepción notable. En la mayoría de las implementaciones, COALESCE
evalúa sus parámetros hasta que llega al primero que no sea NULL, mientras NVL
evalúa todos sus parámetros. Esto es importante por varias razones. Un parámetro después del primer parámetro no NULL podría ser una función, que podría ser computacionalmente costosa, no válida o podría crear efectos secundarios inesperados.
El NULL
literal no tiene tipo en SQL, lo que significa que no está designado como un número entero, carácter ni ningún otro tipo de datos específico . [26] Debido a esto, a veces es obligatorio (o deseable) convertir explícitamente Nulls a un tipo de datos específico. Por ejemplo, si el RDBMS admite funciones sobrecargadas , es posible que SQL no pueda resolver automáticamente la función correcta sin conocer los tipos de datos de todos los parámetros, incluidos aquellos para los que se pasa Null.
La conversión del NULL
literal a un nulo de un tipo específico es posible utilizando lo CAST
introducido en SQL-92 . Por ejemplo:
CAST ( NULO COMO ENTERO )
representa un valor ausente de tipo INTEGER.
El tipo real de Desconocido (distinto o no del propio NULL) varía entre las implementaciones de SQL. Por ejemplo, el siguiente
SELECCIONE 'ok' DONDE ( NULL <> 1 ) ES NULL ;
analiza y ejecuta con éxito en algunos entornos (por ejemplo, SQLite o PostgreSQL ) que unifican un booleano NULL con Desconocido pero no puede analizar en otros (por ejemplo, en SQL Server Compact ). MySQL se comporta de manera similar a PostgreSQL en este sentido (con la pequeña excepción de que MySQL considera VERDADERO y FALSO como no diferentes de los enteros ordinarios 1 y 0). PostgreSQL además implementa un IS UNKNOWN
predicado, que puede usarse para probar si un resultado lógico de tres valores es Desconocido, aunque esto es meramente azúcar sintáctico.
El estándar ISO SQL:1999 introdujo el tipo de datos BOOLEAN en SQL; sin embargo, sigue siendo solo una característica opcional y no principal, codificada como T031. [27]
Cuando está restringido por una NOT NULL
restricción, SQL BOOLEAN funciona como el tipo booleano de otros lenguajes. Sin embargo, sin restricciones, el tipo de datos BOOLEAN, a pesar de su nombre, puede contener los valores de verdad VERDADERO, FALSO y DESCONOCIDO, todos los cuales se definen como literales booleanos según el estándar. El estándar también afirma que NULL y UNKNOWN "pueden usarse indistintamente para significar exactamente lo mismo". [28] [29]
El tipo booleano ha sido objeto de críticas, particularmente por el comportamiento obligatorio del literal DESCONOCIDO, que nunca es igual a sí mismo debido a la identificación con NULL. [30]
Como se analizó anteriormente, en la implementación de SQL en PostgreSQL , Null se usa para representar todos los resultados DESCONOCIDOS, incluido el BOOLEAN DESCONOCIDO. PostgreSQL no implementa el literal DESCONOCIDO (aunque sí implementa el operador IS UNKNOWN, que es una característica ortogonal). La mayoría de los demás proveedores importantes no admiten el tipo booleano (como se define en T031) a partir de 2012. [31] La parte de procedimiento Sin embargo, de PL/SQL de Oracle admite variables BOOLEANAS; a estos también se les puede asignar NULL y el valor se considera el mismo que DESCONOCIDO. [32]
La mala comprensión de cómo funciona Null es la causa de una gran cantidad de errores en el código SQL, tanto en las declaraciones SQL estándar ISO como en los dialectos SQL específicos admitidos por los sistemas de gestión de bases de datos del mundo real. Estos errores suelen ser el resultado de una confusión entre Null y 0 (cero) o una cadena vacía (un valor de cadena con una longitud de cero, representado en SQL como ''
). Sin embargo , el estándar SQL define nulo como diferente tanto de una cadena vacía como del valor numérico 0
. Mientras que Nulo indica la ausencia de cualquier valor, la cadena vacía y el cero numérico representan valores reales.
Un error clásico es el intento de utilizar el operador igual =
en combinación con la palabra clave NULL
para buscar filas con valores nulos. Según el estándar SQL, esta es una sintaxis no válida y generará un mensaje de error o una excepción. Pero la mayoría de las implementaciones aceptan la sintaxis y evalúan dichas expresiones como UNKNOWN
. La consecuencia es que no se encuentran filas, independientemente de si existen filas con valores nulos o no. La forma propuesta de recuperar filas con Nulls es el uso del predicado IS NULL
en lugar de = NULL
.
SELECCIONE * DE alguna tabla DONDE num = NULL ; -- Debería ser "DONDE num ES NULO"
En un ejemplo relacionado, pero más sutil, una WHERE
cláusula o declaración condicional podría comparar el valor de una columna con una constante. A menudo se supone incorrectamente que un valor faltante sería "menor que" o "distinto de" una constante si ese campo contiene Null, pero, de hecho, tales expresiones devuelven Desconocido. A continuación se muestra un ejemplo:
SELECCIONE * DE alguna tabla DONDE num <> 1 ; - Las filas donde num es NULL no se devolverán, - contrariamente a las expectativas de muchos usuarios.
Estas confusiones surgen porque la Ley de Identidad está restringida en la lógica de SQL. Cuando se trata de comparaciones de igualdad utilizando el NULL
literal o el UNKNOWN
valor de verdad, SQL siempre devolverá UNKNOWN
como resultado de la expresión. Esta es una relación de equivalencia parcial y convierte a SQL en un ejemplo de lógica no reflexiva . [33]
De manera similar, los nulos a menudo se confunden con cadenas vacías. Considere la LENGTH
función que devuelve el número de caracteres de una cadena. Cuando se pasa un valor nulo a esta función, la función devuelve nulo. Esto puede generar resultados inesperados si los usuarios no conocen bien la lógica de 3 valores. A continuación se muestra un ejemplo:
SELECCIONE * DE alguna tabla DONDE LONGITUD ( cadena ) < 20 ; -- No se devolverán las filas donde la cadena sea NULL.
Esto se complica por el hecho de que en algunos programas de interfaz de bases de datos (o incluso implementaciones de bases de datos como la de Oracle), NULL se informa como una cadena vacía y las cadenas vacías pueden almacenarse incorrectamente como NULL.
La implementación ISO SQL de Null es objeto de críticas, debates y llamados a cambios. En The Relational Model for Database Management: Version 2 , Codd sugirió que la implementación SQL de Null era defectuosa y debería ser reemplazada por dos marcadores distintos de tipo Null. Los marcadores que propuso significaban "Falta pero aplicable" y "Falta pero inaplicable" , conocidos como valores A y valores I , respectivamente. La recomendación de Codd, de ser aceptada, habría requerido la implementación de una lógica de cuatro valores en SQL. [5] Otros han sugerido agregar marcadores de tipo nulo adicionales a la recomendación de Codd para indicar aún más razones por las que un valor de datos podría estar "faltante", aumentando la complejidad del sistema lógico de SQL. En varias ocasiones, también se han presentado propuestas para implementar múltiples marcadores nulos definidos por el usuario en SQL. Debido a la complejidad de los sistemas lógicos y de manejo de nulos necesarios para admitir múltiples marcadores nulos, ninguna de estas propuestas ha obtenido una aceptación generalizada.
Chris Date y Hugh Darwen , autores de The Third Manifesto , han sugerido que la implementación de SQL Null es inherentemente defectuosa y debería eliminarse por completo, [34] señalando inconsistencias y fallas en la implementación del manejo de SQL Null (particularmente en funciones agregadas). como prueba de que todo el concepto de nulo es defectuoso y debe eliminarse del modelo relacional. [35] Otros, como el autor Fabian Pascal , han manifestado la creencia de que "la forma en que el cálculo de la función debe tratar los valores faltantes no se rige por el modelo relacional". [ cita necesaria ]
Otro punto de conflicto con respecto a los Nulls es que violan el modelo de supuesto de mundo cerrado de las bases de datos relacionales al introducir en él un supuesto de mundo abierto . [36] La suposición del mundo cerrado, en lo que respecta a las bases de datos, establece que "Todo lo declarado por la base de datos, ya sea explícita o implícitamente, es verdadero; todo lo demás es falso". [37] Esta visión supone que el conocimiento del mundo almacenado en una base de datos es completo. Los nulos, sin embargo, operan bajo el supuesto de mundo abierto, en el que algunos elementos almacenados en la base de datos se consideran desconocidos, lo que hace que el conocimiento del mundo almacenado en la base de datos sea incompleto.
{{cite web}}
: Falta o está vacío |url=
( ayuda )