Nulo (SQL) - Null (SQL)

El carácter griego en minúscula omega (ω) se utiliza para representar Null en la teoría de bases de datos .

Null o NULL es un marcador especial que se utiliza en el lenguaje de consulta estructurado 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 , EF Codd , SQL Null sirve para cumplir con el requisito de que todos los verdaderos sistemas de administración de bases de datos relacionales ( RDMS ) 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 Null en la teoría de bases de datos . En SQL, NULLes una palabra reservada que se usa para identificar este marcador.

Un nulo no debe confundirse con un valor de 0. Un valor nulo indica una falta de valor, que no es lo mismo que un valor de cero. Por ejemplo, considere la pregunta "¿Cuántos libros posee Adam?" La respuesta puede ser "cero" ( sabemos que no posee ninguno ) o "nulo" ( no sabemos cuántos posee). En una tabla de base de datos, la columna que informa esta respuesta comenzaría sin valor (marcada con Null) y no se actualizaría con el valor "cero" hasta que hayamos comprobado que Adam no posee libros.

SQL null es un estado, no un valor. Este uso es bastante diferente al de la mayoría de los lenguajes de programación, donde el valor nulo de una referencia significa que no apunta a ningún objeto .

Historia

EF Codd mencionó los valores nulos como un método para representar datos faltantes en el modelo relacional en un artículo de 1975 en el Boletín FDT de ACM - SIGMOD . El artículo de Codd que se cita más comúnmente en relación con la semántica de Null (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 el ú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 nula en operaciones aritméticas, así como las comparaciones que emplean una lógica ternaria (de tres valores) cuando se comparan con nulos; también detalla el tratamiento de Nulls en otras operaciones de conjuntos (este último tema sigue siendo controvertido en la actualidad). 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". 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 .

El estándar SQL 1986 básicamente adoptó la propuesta de Codd después de un prototipo de aplicació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 los argumentos pragmáticos de que era la forma menos costosa de soporte del sistema para la información faltante, lo que salvó al programador de muchas comprobaciones duplicadas a nivel de aplicación (consulte el problema de semipredicado ) y, al mismo tiempo, proporciona al diseñador de la base de datos la opción de no utilizar Nulls 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 alguna funcionalidad de valor perdido, la experiencia práctica con Nulls también condujo a otras características del lenguaje que se basan en Nulls, como ciertas construcciones de agrupación y combinaciones externas. Finalmente, argumentó que, en la práctica, los nulos también terminan siendo utilizados como una forma rápida de parchear un esquema existente cuando necesita evolucionar más allá de su intención original, codificando no la información faltante sino más bien inaplicable; por ejemplo, una base de datos que necesita rápidamente admitir automóviles eléctricos mientras tiene una columna de millas por galón.

Codd indicó en su libro de 1990 The Relational Model for Database Management, Versión 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 la razón por la que faltan datos. En el libro de Codd, estos dos marcadores de tipo nulo se denominan "Valores A" e "Valores I", que representan "Falta pero aplicable" y "Falta pero no aplicable", respectivamente. La recomendación de Codd habría requerido que el sistema lógico de SQL se expandiera para adaptarse a un sistema lógico de cuatro valores. Debido a esta complejidad adicional, la idea de múltiples Nulos 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.

Desafíos

Null ha sido el foco de controversia y una fuente de debate debido a su lógica de tres valores asociada (3VL), los requisitos especiales para su uso en uniones SQL y el manejo especial requerido por las funciones agregadas y los operadores de agrupación SQL. El profesor de informática Ron van der Meyden resumió los diversos problemas como: "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". Si bien se han hecho varias propuestas para resolver estos problemas, la complejidad de las alternativas ha impedido su adopción generalizada.

Propagación nula

Operaciones aritmeticas

Debido a que Null no es un valor de datos, sino un marcador para un valor ausente, el uso de operadores matemáticos en Null da un resultado desconocido, que está representado por Null. En el siguiente ejemplo, multiplicar 10 por Null da como resultado Null:

10 * NULL          -- Result is NULL

Esto puede dar lugar a resultados imprevistos. Por ejemplo, cuando se intenta dividir Null por cero, las plataformas pueden devolver Null en lugar de lanzar una "excepción de datos - división por cero" esperada. 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:

NULL / 0

Concatenación de cadenas

Las operaciones de concatenación de cadenas , que son comunes en SQL, también dan como resultado Null cuando uno de los operandos es Null. El siguiente ejemplo demuestra el resultado Null devuelto al utilizar Null con el ||operador de concatenación de cadenas SQL .

'Fish ' || NULL || 'Chips'   -- Result is NULL

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' || NULL || 'Chips' da como resultado 'Fish Chips'.

Comparaciones con NULL y la lógica de tres valores (3VL)

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 resultar en Verdadero o Falso, pero siempre en un tercer resultado lógico, Desconocido. El resultado lógico de la siguiente expresión, que compara el valor 10 con Null, es Desconocido:

SELECT 10 = NULL       -- Results in Unknown

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:

SELECT NULL OR TRUE   -- Results in True

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 de la izquierda.

SQL implementa tres resultados lógicos, por lo que las implementaciones de SQL deben proporcionar una lógica de tres valores especializada (3VL) . Las normas que rigen la lógica SQL tres valores se muestran en las tablas a continuación ( p y q representan estados lógicos)" Las tablas de verdad SQL utiliza para AND, OR, y no corresponde a un fragmento común de la lógica valioso de tres Kleene y Łukasiewicz ( que difieren en su definición de implicación, sin embargo, SQL no define tal operación).

pag q p O q p Y q p = q
Cierto Cierto Cierto Cierto Cierto
Cierto Falso Cierto Falso Falso
Cierto Desconocido Cierto Desconocido Desconocido
Falso Cierto Cierto Falso Falso
Falso Falso Falso Falso Cierto
Falso Desconocido Desconocido Falso Desconocido
Desconocido Cierto Cierto Desconocido Desconocido
Desconocido Falso Desconocido Falso Desconocido
Desconocido Desconocido Desconocido Desconocido Desconocido
pag NO p
Cierto Falso
Falso Cierto
Desconocido Desconocido

Efecto de Unknown en cláusulas WHERE

La lógica de tres valores de SQL se encuentra en el lenguaje de manipulación de datos (DML) en predicados de comparación de declaraciones y consultas DML. La WHEREcláusula hace que la instrucción DML actúe solo en aquellas filas para las que el predicado se evalúa como Verdadero. Las filas para las cuales los predicados evalúa a falso o desconocido no se actúe sobre él INSERT, UPDATEo DELETEinstrucciones DML, y se eliminen mediante SELECTconsultas. Interpretar Desconocido y Falso como el mismo resultado lógico es un error común que se encuentra al tratar con Nulos. El siguiente ejemplo simple demuestra esta falacia:

SELECT *
FROM t
WHERE 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 SELECTdeclaració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).

Predicados de comparación específicos nulos y específicos de 3VL

Los operadores de comparación de SQL básico 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 NULLy IS NOT NULL(que utilizan una sintaxis de sufijo ) prueban si los datos son o no nulos.

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 es parte de su sintaxis), también usando notación de sufijo. Tienen las siguientes tablas de verdad:

pag p ES VERDADERO p NO ES CIERTO p ES FALSO p NO ES FALSO p ES DESCONOCIDO p NO ES DESCONOCIDO
Cierto Cierto Falso Falso Cierto Falso Cierto
Falso Falso Cierto Cierto Falso Falso Cierto
Desconocido Falso Cierto Falso Cierto Cierto Falso

La función F571 es ortogonal a la presencia del tipo de datos booleano en SQL (discutido 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 función F571 estaba realmente presente en SQL92 , mucho antes de que el tipo de datos booleano se introdujera en el estándar en 1999. Sin embargo, pocos sistemas implementan la función F571; PostgreSQL es uno de los que lo implementa.

La adición de IS UNKNOWN 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 , 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 función F571, es posible emular IS UNKNOWN p repasando todos los argumentos que podrían 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.

Ley del cuarto excluido (en cláusulas DONDE)

En la lógica de tres valores de SQL, la ley del medio excluido , p OR NOT p , ya no se evalúa como verdadera para todo p . Más precisamente, en la lógica de tres valores de SQL, p OR NOT p se desconoce precisamente cuando p es desconocido y verdadero en caso contrario. Debido a que las comparaciones directas con Null dan como resultado el valor lógico desconocido, la siguiente consulta

SELECT * FROM stuff WHERE ( x = 10 ) OR NOT ( x = 10 );

no es equivalente en SQL con

SELECT * FROM stuff;

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 medio excluido permitiría la simplificación del predicado de la cláusula WHERE, de hecho su eliminación. Intentar aplicar la ley del medio excluido al 3VL de SQL es efectivamente una falsa dicotomía . La segunda consulta es en realidad equivalente a:

SELECT * FROM stuff;
-- is (because of 3VL) equivalent to:
SELECT * FROM stuff WHERE ( x = 10 ) OR NOT ( x = 10 ) OR x IS NULL;

Por lo tanto, para simplificar correctamente la primera declaración en SQL se requiere que devolvamos todas las filas en las que x no es nulo.

SELECT * FROM stuff WHERE x IS NOT NULL;

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 medio excluido. Suponiendo que el operador ES DESCONOCIDO está presente, p OR (NO p ) OR ( p ES DESCONOCIDO) es verdadero para cada predicado p . Entre los lógicos, esto se llama ley del cuarto excluido .

Hay algunas expresiones SQL en las que es menos obvio dónde ocurre el falso dilema, por ejemplo:

SELECT 'ok' WHERE 1 NOT IN (SELECT CAST (NULL AS INTEGER))
UNION
SELECT 'ok' WHERE 1 IN (SELECT CAST (NULL AS INTEGER));

no produce filas porque se INtraduce 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 es necesario solo en algunas implementaciones de SQL como PostgreSQL, que lo rechazaría con un error de verificación de tipo de lo contrario. En muchos sistemas, SELECT NULL simple funciona en la subconsulta). El caso que falta arriba es, por supuesto:

SELECT 'ok' WHERE (1 IN (SELECT CAST (NULL AS INTEGER))) IS UNKNOWN;

Efecto de nulo y desconocido en otras construcciones

Uniones

Las uniones evalúan utilizando las mismas reglas de comparación que para las cláusulas WHERE. Por lo tanto, se debe tener cuidado al usar columnas que aceptan valores NULL en los criterios de combinación de SQL. En particular, una tabla que contenga 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 autocombinación de SQL excluirá todas las filas que tengan un Nulo en cualquier lugar. Un ejemplo de este comportamiento se da en la sección que analiza la semántica de valores perdidos de Nulls.

La COALESCEfunción o CASEexpresiones SQL se pueden usar para "simular" la igualdad nula en los criterios de combinación, y los predicados IS NULLy también IS NOT NULLse pueden usar en los criterios de combinación. El siguiente predicado prueba la igualdad de los valores A y B y trata a los nulos como iguales.

(A = B) OR (A IS NULL AND B IS NULL)

Expresiones CASE

SQL proporciona dos tipos de expresiones condicionales . Uno se llama "CASO simple" y funciona como una instrucción de cambio . El otro se denomina "CASO buscado" en el estándar y funciona como un if ... elseif .

Las CASEexpresiones simples usan comparaciones de igualdad implícitas que operan bajo las mismas reglas que las reglas de la WHEREcláusula DML para Null. Por lo tanto, una expresión simpleCASE no puede verificar la existencia de Null directamente. Una comprobación de Null en una CASEexpresión simple siempre da como resultado Desconocido, como se muestra a continuación:

SELECT CASE i WHEN NULL THEN 'Is Null'  -- This will never be returned
              WHEN    0 THEN 'Is Zero'  -- This will be returned when i = 0
              WHEN    1 THEN 'Is One'   -- This will be returned when i = 1
              END
FROM t;

Debido a que la expresión se i = NULLevalúa como Desconocido, independientemente del valor que contenga la columna i (incluso si contiene Null), la cadena 'Is Null'nunca se devolverá.

Por otro lado, una CASEexpresión "buscada" puede usar predicados como IS NULLy IS NOT NULLen sus condiciones. El siguiente ejemplo muestra cómo utilizar una CASEexpresión buscada para comprobar correctamente si existe un valor nulo:

SELECT CASE WHEN i IS NULL THEN 'Null Result'  -- This will be returned when i is NULL
            WHEN     i = 0 THEN 'Zero'         -- This will be returned when i = 0
            WHEN     i = 1 THEN 'One'          -- This will be returned when i = 1
            END
FROM t;

En la CASEexpresión buscada , la cadena 'Null Result'se devuelve para todas las filas en las que i es nulo.

El dialecto de SQL de Oracle proporciona una función incorporada DECODEque se puede utilizar en lugar de las simples expresiones CASE y considera dos nulos iguales.

SELECT DECODE(i, NULL, 'Null Result', 0, 'Zero', 1, 'One') FROM t;

Finalmente, todas estas construcciones devuelven un NULL si no se encuentra ninguna coincidencia; tienen una ELSE NULLcláusula predeterminada .

Declaraciones IF en extensiones de procedimiento

SQL / PSM (módulos almacenados persistentes de SQL) define extensiones de procedimiento para SQL, como la IFdeclaración. Sin embargo, los principales proveedores de SQL han incluido históricamente sus propias extensiones de procedimiento 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 IFdeclaración.

IF i = NULL THEN
      SELECT 'Result is True'
ELSEIF NOT(i = NULL) THEN
      SELECT 'Result is False'
ELSE
      SELECT 'Result is Unknown';

La IFdeclaración realiza acciones solo para aquellas comparaciones que se evalúan como Verdadero. Para las declaraciones que se evalúan como Falso o Desconocido, la IFdeclaración pasa el control a la ELSEIFcláusula y, finalmente, a la ELSEclá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.

Análisis de la semántica de valores perdidos nulos de SQL

El trabajo pionero de T. Imieliński y W. Lipski Jr. (1984) proporcionó un marco en el que evaluar la semántica prevista de varias propuestas para implementar la semántica de valores perdidos, que se conoce como Imieliński-Lipski Algebras . Esta sección sigue aproximadamente al capítulo 19 del libro de texto "Alice". Una presentación similar aparece en la revisión de Ron van der Meyden, §10.4.

En selecciones y proyecciones: representación débil

Las construcciones que representan la información faltante, como las tablas Codd, en realidad están destinadas a representar un conjunto de relaciones, una para cada posible instanciación de sus parámetros; en el caso de las tablas Codd, esto significa la sustitución de Nulls por algún valor concreto. Por ejemplo,

 

Emp
Nombre La edad
Jorge 43
Harriet NULL
Charles 56
EmpH22
Nombre La edad
Jorge 43
Harriet 22
Charles 56
EmpH37
Nombre La edad
Jorge 43
Harriet 37
Charles 56
La tabla Codd Emp puede representar la relación EmpH22 o EmpH37 , como se muestra en la imagen.

Se dice que un constructo (como una tabla 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 que se ven 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) construct T , q eleva 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

SELECT * FROM Emp WHERE Age = 22;

debe incluir la posibilidad de que exista una relación como EmpH22. Sin embargo, las tablas de Codd no pueden representar la disyunción "resultado con posiblemente 0 o 1 filas". Sin embargo, un dispositivo, principalmente de interés teórico, llamado tabla condicional (o tabla c) puede representar tal respuesta:

Resultado
Nombre La edad condición
Harriet ω 1 ω 1 = 22

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 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 (eliminadas) sobre una construcción devuelvan una representación solo para información segura , es decir, si es válida para todas las instanciaciones (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 los valores que se utilicen para reemplazar los 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 la consulta está realmente 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 Codd son un sistema de representación débil si el lenguaje de consulta se limita 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

Si se consideran uniones o uniones: ni siquiera una representación débil

Considere la siguiente consulta sobre la misma tabla Codd Emp de la sección anterior:

SELECT Name FROM Emp WHERE Age = 22
UNION
SELECT Name FROM Emp WHERE Age <> 22;

Cualquiera que sea el valor concreto que uno elija para la NULLedad de Harriet, la consulta anterior devolverá la columna completa de nombres de cualquier modelo de Emp , pero cuando la consulta (levantada) se ejecuta en Emp , Harriet siempre faltará, es decir, tenemos :

Resultado de la consulta en Emp :
Nombre
Jorge
Charles
Resultado de la consulta en cualquier modelo de Emp :
Nombre
Jorge
Harriet
Charles

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 la información faltante, lo que significa que las consultas sobre ellas ni siquiera informan 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 alguna información segura no se reportara cuando la consulta anterior se ejecutó en la tabla Codd Emp.

Para combinaciones naturales , el ejemplo necesario para mostrar que cierta información puede no ser reportada por alguna consulta es un poco más complicado. Considere la mesa

J
F1 F2 F3
11 NULL 13
21 NULL 23
31 32 33

y la consulta

SELECT F1, F3 FROM
  (SELECT F1, F2 FROM J) AS F12
  NATURAL JOIN
  (SELECT F2, F3 FROM J) AS F23;
Resultado de la consulta en J:
F1 F3
31 33
Resultado de la consulta en cualquier modelo de J:
F1 F3
11 13
21 23
31 33

La intuición de lo que sucede arriba es que las tablas Codd que representan las proyecciones en las subconsultas pierden el rastro del 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 ingenuas, es computacionalmente menos costoso que las tablas c discutidas 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 ninguna negación en la selección (y tampoco usan ninguna diferencia de conjunto). 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

Verifique las restricciones y las claves externas

El lugar principal en el que la lógica de tres valores de SQL se cruza con el lenguaje de definición de datos de SQL (DDL) 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 WHEREcláusula DML . Mientras que una WHEREcláusula DML debe evaluar como Verdadero para una fila, una restricción de verificación no debe evaluar 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.

CREATE TABLE t (
     i INTEGER,
     CONSTRAINT ck_i CHECK ( i < 0 AND i = 0 AND 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 medio excluido es una tautología para las restricciones CHECK , lo que significa que siempre tiene éxito. Además, suponiendo que los Nulos se interpreten como valores existentes pero desconocidos, algunos CHECK patológicos como el anterior permiten la inserción de Nulos que nunca podrían ser reemplazados por ningún valor no nulo. CHECK (p OR NOT p)

Para restringir una columna para que rechace Nulos, NOT NULLse puede aplicar la restricción, como se muestra en el siguiente ejemplo. La NOT NULLrestricción es semánticamente equivalente a una restricción de verificación con un IS NOT NULLpredicado.

CREATE TABLE t ( i INTEGER NOT NULL );

De forma predeterminada, las restricciones de comprobación contra claves externas se realizan correctamente si alguno de los campos de dichas claves es nulo. Por ejemplo, la mesa

CREATE TABLE Books
( title VARCHAR(100),
  author_last VARCHAR(20),
  author_first VARCHAR(20),
FOREIGN KEY (author_last, author_first)
  REFERENCES Authors(last_name, first_name));

permitiría la inserción de filas donde author_last o author_first son NULLindependientemente de cómo se define la tabla Authors o lo que contiene. Más precisamente, un nulo en cualquiera de estos campos permitiría cualquier valor en el otro, incluso si no se encuentra en la tabla Autores. Por ejemplo, si Autores solo contuviera ('Doe', 'John'), entonces ('Smith', NULL)satisfaría la restricción de clave externa. SQL-92 agregó dos opciones adicionales para reducir las coincidencias en tales casos. Si MATCH PARTIALse agrega después de la REFERENCESdeclaración, cualquier no nulo debe coincidir con la clave externa, por ejemplo, ('Doe', NULL)seguiría coincidiendo, pero ('Smith', NULL)no. Finalmente, si MATCH FULLse agrega ('Smith', NULL), tampoco coincidiría con la restricción, pero (NULL, NULL)aún así la coincidiría.

Uniones externas

Ejemplo de consulta de combinación externa SQL con marcadores de posición nulos en el conjunto de resultados. Los marcadores nulos están representados por la palabra en lugar de datos en los resultados. Los resultados son de Microsoft SQL Server , como se muestra en SQL Server Management Studio.NULL

Las uniones externas de SQL , incluidas las uniones externas izquierdas, las uniones externas derechas y las uniones externas completas, generan automáticamente Nulos como marcadores de posición para los valores faltantes en las tablas relacionadas. Para las combinaciones externas izquierdas, por ejemplo, los nulos se producen en lugar de las filas que faltan en la tabla que aparecen en el lado derecho del LEFT OUTER JOINoperador. El siguiente ejemplo simple usa dos tablas para demostrar la producción de marcadores de posición nulos en una combinación externa izquierda.

La primera tabla ( Empleado ) contiene los números de identificación y los nombres de los empleados, mientras que la segunda tabla ( PhoneNumber ) contiene los números de identificación de los empleados y los números de teléfono relacionados , como se muestra a continuación.

Empleado
IDENTIFICACIÓN Apellido Primer nombre
1 Johnson José
2 Luis Larry
3 Thompson Thomas
4 Patterson Patricia
Número de teléfono
IDENTIFICACIÓN Número
1 555-2323
3 555-9876

La siguiente consulta SQL de ejemplo realiza una combinación externa izquierda en estas dos tablas.

SELECT e.ID, e.LastName, e.FirstName, pn.Number
FROM Employee e
LEFT OUTER JOIN PhoneNumber pn
ON e.ID = pn.ID;

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.

Resultado de la consulta
IDENTIFICACIÓN Apellido Primer nombre Número
1 Johnson José 555-2323
2 Luis Larry NULL
3 Thompson Thomas 555-9876
4 Patterson Patricia NULL

Funciones agregadas

SQL define funciones agregadas para simplificar los cálculos agregados del lado del servidor sobre los datos. A excepción de la COUNT(*)función, todas las funciones agregadas realizan un paso de eliminación de nulos, por lo que los nulos no se incluyen en el resultado final del cálculo.

Tenga en cuenta que la eliminación de Null no es equivalente 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):

I j
150 150
200 200
250 250
NULL 0

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).

La salida de una función agregada también puede ser nula. Aquí hay un ejemplo:

SELECT COUNT(*), MIN(e.Wage), MAX(e.Wage)
FROM Employee e
WHERE e.LastName LIKE '%Jones%';

Esta consulta siempre generará exactamente una fila, contando el número de empleados cuyo apellido contiene "Jones" y dando 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 Nulo que representa la ausencia de un valor. El resultado sería:

CONTAR(*) MIN (e. Salario) MAX (e. Salario)
0 NULL NULL

Cuando dos valores nulos son iguales: agrupación, ordenación y algunas operaciones de conjunto

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". Esta definición de no distinto permite a SQL agrupar y ordenar Nulos cuando GROUP BYse usa la cláusula (y otras palabras clave que realizan la agrupación).

Otras operaciones, cláusulas y palabras clave de SQL utilizan "no distintas" en su tratamiento de los nulos. Estos incluyen los siguientes:

  • PARTITION BY cláusula de funciones de clasificación y ventanas como ROW_NUMBER
  • UNION, INTERSECTY EXCEPToperador, que tratan NULL como el mismo para la comparación propósitos de fila / eliminación
  • DISTINCTpalabra clave utilizada en SELECTconsultas

El principio de que los nulos no son iguales entre sí (sino que el resultado es Desconocido) se viola efectivamente en la especificación de SQL para el UNIONoperador, que identifica los nulos entre sí. 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, las de una WHEREclá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 "en un nivel de detalle más bajo que las pruebas de igualdad en la evaluación de operaciones de recuperación".

El estándar SQL no define explícitamente un orden de clasificación predeterminado para los nulos. En cambio, en los sistemas conformes, los Nulos se pueden ordenar antes o después de todos los valores de datos utilizando las cláusulas NULLS FIRSTo NULLS LASTde la ORDER BYlista, respectivamente. Sin embargo, no todos los proveedores de DBMS implementan esta funcionalidad. Los proveedores que no implementan esta funcionalidad pueden especificar diferentes tratamientos para la clasificación nula en el DBMS.

Efecto en la operación de índice

Algunos productos SQL no indexan claves que contienen NULL. Por ejemplo, las versiones de PostgreSQL anteriores a 8.3 no lo hicieron, con la documentación para un índice de árbol B que indica que

Los árboles B pueden manejar consultas de igualdad y rango en 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 utilizando 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 que el índice impone la unicidad, los NULL se excluyen del índice y la unicidad no se aplica entre los NULL. Nuevamente, citando de la documentación de PostgreSQL :

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 escalares nulas.

Otro método de indexar Nulos implica manejarlos como no distintos de acuerdo con el comportamiento definido por SQL: 2003. Por ejemplo, la documentación de Microsoft SQL Server establece lo siguiente:

Para fines de indexación, los valores NULL se comparan como iguales. Por lo tanto, no se puede crear un índice único o una restricción ÚNICA si las claves son NULL en más de una fila. Seleccione columnas definidas como NOT NULL cuando se eligen columnas para un índice único o una restricción única.

Ambas estrategias de indexación son coherentes con el comportamiento de Nulls definido por SQL: 2003. Debido a que las metodologías de indexación no están definidas explícitamente por el estándar SQL: 2003, las estrategias de indexación para Nulls quedan enteramente en manos de los proveedores para que las diseñen e implementen.

Funciones de manejo nulo

SQL define dos funciones para manejar explícitamente Nulos: NULLIFy COALESCE. Ambas funciones son abreviaturas de expresiones buscadasCASE .

NULLIF

La NULLIFfunción acepta dos parámetros. Si el primer parámetro es igual al segundo parámetro, NULLIFdevuelve Null. De lo contrario, se devuelve el valor del primer parámetro.

NULLIF(value1, value2)

Por lo tanto, NULLIFes una abreviatura de la siguiente CASEexpresión:

CASE WHEN value1 = value2 THEN NULL ELSE value1 END

JUNTARSE

La COALESCEfunción acepta una lista de parámetros, devolviendo el primer valor no nulo de la lista:

COALESCE(value1, value2, value3, ...)

COALESCEse define como una abreviatura de la siguiente CASEexpresión SQL :

CASE WHEN value1 IS NOT NULL THEN value1
     WHEN value2 IS NOT NULL THEN value2
     WHEN value3 IS NOT NULL THEN value3
     ...
     END

Algunos DBMS SQL implementan funciones específicas del proveedor similares a COALESCE. Algunos sistemas (por ejemplo, Transact-SQL ) implementan una ISNULLfunción u otras funciones similares que son funcionalmente similares a COALESCE. (Consulte Isfunciones para obtener más información sobre las ISfunciones de Transact-SQL).

NVL

La NVLfunción de Oracle acepta dos parámetros. Devuelve el primer parámetro no NULL o NULL si todos los parámetros son NULL.

Una COALESCEexpresión se puede convertir en una NVLexpresión equivalente así:

COALESCE ( 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 en el NVL(SALARY, 0)que dice, 'si SALARYes NULL, reemplácelo con el valor 0'.

Sin embargo, existe una excepción notable. En la mayoría de las implementaciones, COALESCEevalúa sus parámetros hasta que alcanza el primero que no es NULL, mientras NVLevalú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, inválida o podría crear efectos secundarios inesperados.

Tipificación de datos de nulo y desconocido

El NULL literal no tiene tipo en SQL, lo que significa que no está designado como un entero, carácter o cualquier otro tipo de datos específico . Debido a esto, a veces es obligatorio (o deseable) convertir explícitamente Nulls en 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 NULLliteral a un nulo de un tipo específico es posible usando el CASTintroducido en SQL-92 . Por ejemplo:

CAST (NULL AS INTEGER)

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, lo siguiente

SELECT 'ok' WHERE (NULL <> 1) IS 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 a este respecto (con la excepción menor de que MySQL considera VERDADERO y FALSO como iguales a los enteros ordinarios 1 y 0). PostgreSQL además implementa un IS UNKNOWNpredicado, que se puede usar para probar si un resultado lógico de tres valores es Desconocido, aunque esto es simplemente azúcar sintáctico.

Tipo de datos BOOLEAN

El estándar ISO SQL: 1999 introdujo el tipo de datos BOOLEAN en SQL, sin embargo, sigue siendo solo una característica opcional, no principal, codificada como T031.

Cuando está restringido por una NOT NULLrestricció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 de acuerdo con el estándar. El estándar también afirma que NULL y UNKNOWN "pueden usarse indistintamente para significar exactamente lo mismo".

El tipo booleano ha sido objeto de críticas, particularmente debido al comportamiento obligatorio del literal UNKNOWN, que nunca es igual a sí mismo debido a la identificación con NULL.

Como se mencionó anteriormente, en la implementación de SQL de PostgreSQL , Null se usa para representar todos los resultados DESCONOCIDOS, incluido el BOOLEANO DESCONOCIDO. PostgreSQL no implementa el literal UNKNOWN (aunque implementa el operador IS UNKNOWN, que es una característica ortogonal). La mayoría de los otros proveedores importantes no admiten el tipo booleano (como se define en T031) a partir de 2012. La parte de procedimiento del PL de Oracle / SQL admite BOOLEAN sin embargo variables; a estos también se les puede asignar NULL y el valor se considera el mismo que DESCONOCIDO.

Controversia

Errores comunes

La incomprensió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 compatibles con los sistemas de administración de bases de datos del mundo real. Estos errores suelen ser el resultado de la 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 ''). 0Sin embargo, el estándar SQL define nulo como diferente tanto de una cadena vacía como del valor numérico . Mientras que Null 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 usar el operador igual =en combinación con la palabra clave NULLpara buscar filas con Nulos. Según el estándar SQL, esta es una sintaxis no válida y dará lugar a un mensaje de error o una excepción. Pero la mayoría de las implementaciones aceptan la sintaxis y evalúan tales expresiones para UNKNOWN. La consecuencia es que no se encuentran filas, independientemente de si existen filas con Nulos o no. La forma propuesta de recuperar filas con Nulls es el uso del predicado en IS NULLlugar de = NULL.

SELECT *
FROM sometable
WHERE num = NULL;  -- Should be "WHERE num IS NULL"

En un ejemplo relacionado, pero más sutil, una WHEREcláusula o declaración condicional podría comparar el valor de una columna con una constante. A menudo se asume incorrectamente que un valor perdido sería "menor que" o "no igual a" una constante si ese campo contiene Null, pero, de hecho, tales expresiones devuelven Desconocido. A continuación se muestra un ejemplo:

SELECT *
FROM sometable
WHERE num <> 1;  -- Rows where num is NULL will not be returned,
                 -- contrary to many users' expectations.

Estas confusiones surgen porque la Ley de Identidad está restringida en la lógica de SQL. Cuando se trata de comparaciones de igualdad usando el NULLliteral o el UNKNOWNvalor de verdad, SQL siempre regresará UNKNOWNcomo resultado de la expresión. Esta es una relación de equivalencia parcial y hace que SQL sea un ejemplo de lógica no reflexiva .

Del mismo modo, los valores nulos a menudo se confunden con cadenas vacías. Considere la LENGTHfunción, que devuelve el número de caracteres en una cadena. Cuando se pasa un Null a esta función, la función devuelve Null. Esto puede conducir a resultados inesperados, si los usuarios no están bien versados ​​en la lógica de 3 valores. A continuación se muestra un ejemplo:

SELECT *
FROM sometable
WHERE LENGTH(string) < 20; -- Rows where string is NULL will not be returned.

Esto se complica por el hecho de que en algunos programas de interfaz de base de datos (o incluso implementaciones de base de datos como la de Oracle), NULL se informa como una cadena vacía y las cadenas vacías pueden almacenarse incorrectamente como NULL.

Criticas

La implementación ISO SQL de Null es objeto de críticas, debates y llamados al cambio. En The Relational Model for Database Management: Versión 2 , Codd sugirió que la implementación de SQL de Null era defectuosa y debería ser reemplazada por dos marcadores distintos de tipo Null. Los marcadores que propuso fueron reposar durante "Missing pero aplicable" y "Missing pero que no se aplican" , conocido como A-valores y los valores I , respectivamente. La recomendación de Codd, de aceptarse, habría requerido la implementación de una lógica de cuatro valores en SQL. 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", lo que aumenta la complejidad del sistema lógico de SQL. En varias ocasiones, también se han presentado propuestas para implementar múltiples marcadores Null 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 de nulos, ninguna de estas propuestas ha ganado 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 debe eliminarse por completo, 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. 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 perdidos no se rige por el modelo relacional".

Supuesto de mundo cerrado

Otro punto de conflicto con respecto a los nulos es que violan el modelo de suposición de mundo cerrado de las bases de datos relacionales al introducir una suposición de mundo abierto en él. La suposición del mundo cerrado, en lo que respecta a las bases de datos, establece que "Todo lo que dice la base de datos, ya sea explícita o implícitamente, es verdadero; todo lo demás es falso". Esta vista asume que el conocimiento del mundo almacenado en una base de datos es completo. Sin embargo, los nulos 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 almacenado del mundo en la base de datos sea incompleto.

Ver también

Referencias

Otras lecturas

enlaces externos