Documentación Firebird → Base de Datos Firebird → Guía de NULL en Firebird → NULL en expresiones |
Como muchos de nosotros hemos encontrado, para nuestro disgusto, NULL es contagioso: úsalo en una expresión numérica, texto o fecha/hora y el resultado siempre es NULL. Úsalo en una expresión lógica y el resultado depende del tipo de operación y el resto de valores implicados.
Por cierto, nota que en versiones anteriores a Firebird 2.0 es normalmente ilegal usar la constante NULL directamente en operaciones o comparaciones. Cuando veas NULL en las expresiones siguientes, léelas como “un campo, variable u otra expresión que resuelve en NULL”.
Las expresiones en esta lista siempre devuelven NULL:
1 + 2 + 3 + NULL
'Hogar ' || 'dulce ' || NULL
MiCampo = NULL
MiCampo <> NULL
NULL = NULL
not (NULL)
Si tienes dificultades en entender por qué, recuerda que NULL significa “desconocido”. Además mira en la siguiente tabla donde hay explicaciones por caso. En la tabla, no hemos escrito NULL en las expresiones (como ya hemos dicho, es, a menudo, ilegal); en vez de ello, hemos usado dos entidades A y B que son ambas NULL. A y B pueden ser campos, variables o subexpresiones enteras en su derecho – como son NULL, se comportan de la misma manera que expresiones cerradas.
Tabla 3. Operaciones sobre entidades NULL A y B
Si A y B son NULL, entonces: | Es: | Porque: |
---|---|---|
1 + 2 + 3 + A | NULL | Si A es desconocido, entonces 6+A también es desconocido. |
'Hogar ' || 'dulce ' || A | NULL | Si A es desconocido, entonces 'Hogar dulce ' || A es también desconocido. |
MiCampo = A | NULL | Si A es desconocido, no puedes decir que MiCampo tenga el mismo valor… |
MiCampo <> A | NULL | ...ni puedes decir que MiCampo tenga distinto valor! |
A = B | NULL | Con A y B desconocidos, es imposible saber si son iguales. |
not (A) | NULL | Si A es desconocido, su inverso también. |
Hemos visto que not(NULL) devuelve NULL. Para los operadores and y or, las cosas son un poco más complicadas:
NULL or false = NULL
NULL or true = true
NULL or NULL = NULL
NULL and false = false
NULL and true = NULL
NULL and NULL = NULL
El SQL de Firebird no tiene un dato de tipo booleano (lógico); no hay unas constantes true o false existentes. En la columna de la izquierda de la siguiente tabla (true) y (false) representan expresiones que devuelven true/false.
Tabla 4. Operaciones lógicas (booleanas) sobre una entidad NULL A
Si A es NULL, entonces: | Es: | Porque: |
---|---|---|
A or (false) | NULL | “A or false” siempre tiene el valor de A, que es desconocido. |
A or (true) | true | “A or true” siempre es true. El valor de A no importa. |
A or A | NULL | “A or A” siempre equivale a A, que es NULL. |
A and (false) | false | “A and false” es siempre false. El valor de A no importa. |
A and (true) | NULL | “A and true” siempre tiene el valor de A, el cuál es desconocido. |
A and A | NULL | “A and A” siempre equivale a A, que es NULL. |
Todos estos resultados están en concordancia con la lógica booleana. El hecho de que, para calcular “X or true” y “X and false”, simplemente no necesites saber el valor de X, es también la base de una característica que conocemos en varios lenguajes de programación: evaluación de circuitos cortos booleanos.
Los resultados de circuitos cortos obtenidos arriba, pueden llevarte a las siguientes ideas:
0 veces x equivale a 0 para cada x. Por tanto, igual que el valor de x es desconocido, 0 * x es 0. (Nota: esto sólo sucede si el tipo de dato de x sólo contiene números, no NaN o infinitos).
La cadena vacía está ordenada lexicográficamente antes de cada otra cadena. Por tanto S >= '' es verdad siempre independientemente del valor de S.
Cada valor equivale a sí mismo, independientemente de si es desconocido o no. Por tanto, aunque A = B justificadamente se devuelve NULL si A y B son entidades NULL diferentes, A = A siempre debería devolver true, igual que A es NULL.
¿Cómo está esto implementado en el SQL de Firebird? Bueno, siento informarte que, a pesar de esta convincente lógica – y la analogía con los resultados explicados arriba – las siguientes expresiones se resuelven todas con NULL:
0 * NULL
NULL >= ''
'' <= NULL
A = A (con A como un campo o variable NULL)
Demasiado para la coherencia.
En funciones agregadas como COUNT, SUM, AVG, MAX, y MIN, NULL se maneja de manera diferente: para calcular el resultado, sólo se tienen en consideración los campos con valores no-NULL. Esto es, si tienes esta tabla:
MiTabla
ID | Nombre | Sueldo |
---|---|---|
1 | Juan | 37 |
2 | Perico | <NULL> |
3 | Andrés | 5 |
4 | Roberto | 12 |
5 | Antonio | <NULL> |
...la sentencia select sum(Sueldo) from MiTabla devuelve 54, que es 37+5+12. Si sumáramos todos los valores, el resultado debería haber sido NULL. Para AVG, los campos no-NULL son sumados y la suma dividida entre el número de campos no-NULL.
Hay una excepción en esta regla: COUNT(*) devuelve el número de todas las filas, incluidas todas aquellas con campos en NULL. Pero COUNT(NombreDeCampo) se comporta como las otras funciones agregadas y cuenta aquellas filas que tienen campos con contenido no-NULL.
Otra cosa a tener en cuenta: COUNT(*) y COUNT(NombreDeCampo) jamás devuelven NULL: si no hay filas en el grupo, ambas funciones devuelven 0. Además, COUNT(NombreDeCampo) devuelve 0 si todos los campos NombreDeCampo del grupo son NULL. Las otras funciones agregadas devuelven NULL en tales casos. Ten en cuenta que SUM devuelve NULL si se usa en un grupo de registros vacío, lo que es contrario a la lógica común.
Documentación Firebird → Base de Datos Firebird → Guía de NULL en Firebird → NULL en expresiones |