¿Por qué Oracle 9i trata una cadena vacía como NULL?

216

Sé que considera '' como NULL, pero eso no hace mucho para decirme por qué es así. Según entiendo las especificaciones SQL, '' no es lo mismo que NULL: uno es un dato válido y el otro indica la ausencia de esa misma información.

No dude en especular, pero indique si ese es el caso. Si hay alguien de Oracle que pueda comentarlo, ¡sería fantástico!

Chris R
fuente
99
Siéntete libre de especular? De alguna manera, no creo que eso le proporcione el mejor conjunto de respuestas ..
SCdF
1
Supongo que no, pero no estaba seguro de que hubiera alguna certeza sobre el tema, así que pensé que abriría las puertas. Parece haber funcionado bien, hasta ahora.
Chris R
Relacionado: dba.stackexchange.com/q/49744/56961
AlikElzin-kilaka

Respuestas:

216

Creo que la respuesta es que Oracle es muy, muy viejo.

En los viejos tiempos antes de que hubiera un estándar SQL, Oracle tomó la decisión de diseño de que las cadenas vacías en VARCHAR/ VARCHAR2columnas eran NULLy que solo había un sentido de NULL (hay teóricos relacionales que diferenciarían entre datos que nunca se han solicitado, datos donde la respuesta existe pero el usuario no la conoce, datos donde no hay respuesta, etc., todos los cuales constituyen algún sentido de NULL).

Para cuando llegó el estándar SQL y acordó que NULLy la cadena vacía eran entidades distintas, ya había usuarios de Oracle que tenían un código que suponía que los dos eran equivalentes. Así que, básicamente, Oracle se quedó con las opciones de romper el código existente, violar el estándar SQL o introducir algún tipo de parámetro de inicialización que cambiaría la funcionalidad de un número potencialmente grande de consultas. Violar el estándar SQL (en mi humilde opinión) fue la menos perjudicial de estas tres opciones.

Oracle ha dejado abierta la posibilidad de que el VARCHARtipo de datos cambie en una versión futura para cumplir con el estándar SQL (razón por la cual todo el mundo usa VARCHAR2en Oracle ya que el comportamiento de ese tipo de datos se mantendrá igual en el futuro).

Justin Cave
fuente
60

Tom Kyte Vicepresidente de Oracle:

Un varchar de longitud CERO se trata como NULL.

'' no se trata como NULL.

'' cuando se asigna a un char (1) se convierte en '' (los tipos de char son cadenas rellenas en blanco).

'' cuando se asigna a un varchar2 (1) se convierte en '' que es una cadena de longitud cero y una cadena de longitud cero es NULL en Oracle (no es larga '')

Brian
fuente
17
Wow, Tom es bastante sarcástico. Dado que las preguntas pertenecen a una divergencia atroz con respecto a SQL92, pensaría que sería menos agresivo al respecto ... aunque podría estar cansado de responder.
Chris R
8
Lo mejor de Tom es que obtienes una respuesta clara, que establece exactamente lo que piensa. Busque algunos de los comentarios en los que la gente ha usado texto hable en Ask Tom
Chris Gill el
99
Pero sería más preciso si la segunda línea se cambiara a '' no siempre se trata como NULL.
ypercubeᵀᴹ
2
@ypercube La cita no se vuelve más precisa al cambiar la palabra realmente utilizada por Tom. Si crees que Tom lo redactó confusamente, mmm. Tal vez. Creo que es perfecto . Las situaciones más confusas surgen cuando ''se convierte implícitamente en un VARCHAR2, como el cast('' as char(1)) is nullque es ... sorprendentemente VERDADERO
sehe
1
@sehe la parte confusa para mí es seleccionar 1 de dual donde ('' es nulo)
matt freake
20

Sospecho que esto tiene mucho más sentido si piensas en Oracle como probablemente lo hicieron los desarrolladores anteriores, como un backend glorificado para un sistema de entrada de datos. Cada campo en la base de datos correspondía a un campo en una forma que un operador de entrada de datos vio en su pantalla. Si el operador no escribió nada en un campo, ya sea "fecha de nacimiento" o "dirección", entonces los datos para ese campo son "desconocidos". No hay forma de que un operador indique que la dirección de alguien es realmente una cadena vacía, y eso no tiene mucho sentido de todos modos.

usuario67897
fuente
55
Eso solo tiene sentido si asume que todos los campos en un sistema de entrada de datos son obligatorios. Una no respuesta a un campo no obligatorio (por ejemplo, "Nombre del perro") es válida, por lo que una cadena vacía todavía tiene un propósito distinto de NULL. Incluso con esa suposición, dudo que los primeros desarrolladores pensaran en Oracle como un "backend glorificado para un sistema de entrada de datos", por lo que no estoy seguro de que esta respuesta tenga sentido.
Jared
19

La documentación de Oracle alerta a los desarrolladores sobre este problema, retrocediendo al menos hasta la versión 7.

Oracle eligió representar NULLS mediante la técnica del "valor imposible". Por ejemplo, un NULL en una ubicación numérica se almacenará como "menos cero", un valor imposible. Cualquier cero negativo resultante de los cálculos se convertirá a cero positivo antes de almacenarse.

Oracle también eligió, erróneamente, considerar la cadena VARCHAR de longitud cero (la cadena vacía) como un valor imposible y una opción adecuada para representar NULL. Resulta que la cadena vacía está lejos de ser un valor imposible. ¡Incluso es la identidad bajo la operación de concatenación de cadenas!

La documentación de Oracle advierte a los diseñadores y desarrolladores de bases de datos que alguna versión futura de Oracle podría romper esta asociación entre la cadena vacía y NULL, y romper cualquier código que dependa de esa asociación.

Existen técnicas para marcar NULLS que no sean valores imposibles, pero Oracle no los usó.

(Estoy usando la palabra "ubicación" arriba para significar la intersección de una fila y una columna).

Walter Mitty
fuente
La documentación de Oracle advierte a los diseñadores y desarrolladores de bases de datos que alguna versión futura de Oracle podría romper esta asociación entre la cadena vacía y NULL, y romper cualquier código que dependa de esa asociación . ¿Podría proporcionarnos referencia para esta declaración?
Piotr Dobrogost el
2

La cadena vacía es lo mismo que NULL simplemente porque es el "mal menor" en comparación con la situación cuando las dos (cadena vacía y nula) no son lo mismo.

En los idiomas donde NULL y String vacío no son lo mismo, uno siempre debe verificar ambas condiciones.

Alex Kreutznaer
fuente
Simplemente establezca la not nullrestricción en su columna y verifique solo en la cadena vacía.
Egor Skriptunoff
66
Verificar ambas condiciones es trivial: WHERE Field <> ''devuelve verdadero solo si el campo no es NULL y no está vacío, en bases de datos con comportamiento ANSI para cadenas vacías.
1

Según los documentos oficiales de 11g

Oracle Database actualmente trata un valor de carácter con una longitud de cero como nulo. Sin embargo, esto puede no seguir siendo cierto en futuras versiones, y Oracle recomienda que no trate las cadenas vacías de la misma manera que las nulas.

Posibles razones

  1. val IS NOT NULL es más legible que val != ''
  2. No es necesario verificar ambas condiciones val != '' and val IS NOT NULL
Clasificador
fuente
55
En una base de datos totalmente compatible con ANSI, no tiene que verificar ambas condiciones. val <> ''Ya excluye NULL. Quizás quisiste decir val = '' OR val IS NULL. ¡Pero las cadenas vacías que no se comparan como NULL son útiles !
ErikE
Estoy de acuerdo con la parte de comparación.
Clasificador
0

Ejemplo del libro

   set serveroutput on;   
    DECLARE
    empty_varchar2 VARCHAR2(10) := '';
    empty_char CHAR(10) := '';
    BEGIN
    IF empty_varchar2 IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_varchar2 is NULL');
    END IF;


    IF '' IS NULL THEN
    DBMS_OUTPUT.PUT_LINE(''''' is NULL');
    END IF;

    IF empty_char IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
    ELSIF empty_char IS NOT NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
    END IF;

    END;
zloctb
fuente
-1

Porque no tratarlo como NULL tampoco es particularmente útil.

Si comete un error en esta área en Oracle, generalmente lo nota de inmediato. Sin embargo, en el servidor SQL parecerá funcionar, y el problema solo aparece cuando alguien ingresa una cadena vacía en lugar de NULL (quizás de una biblioteca de cliente .net, donde nulo es diferente de "", pero generalmente los trata de la misma manera )

No digo que Oracle tenga razón, pero me parece que ambas formas son aproximadamente igual de malas.

erikkallen
fuente
2
Mucho, mucho más fácil de depurar. Además, si ve una celda o entrada vacía en la pantalla, sabe que los datos en la base de datos son nulos. En otras bases de datos donde '' <> NULL, no puede "ver" si los datos son nulos o '', esto conduce a errores muy furtivos. '' = nulo es la opción más sensata, incluso si no es estándar.
Lucio M. Tato
2
“En otros DB donde '' <> NULL, no puede" ver "si los datos son nulos o ''” => Por lo general, las herramientas de DB muestran NULL de manera diferente a las cadenas vacías. En realidad, incluso Oracle SQL Developer muestra NULL como "(nulo)". Supongo que esto es para distinguir NULL del espacio en blanco, pero no está relacionado con la diferencia entre NULL y cadenas vacías.
Didier L
-6

De hecho, no he tenido más que dificultades para tratar con Oracle, incluidos los valores de fecha y hora no válidos (no se pueden imprimir, convertir ni nada, solo mirar con la función DUMP ()) que están permitidos a insertar en la base de datos, al parecer, a través de algunos con errores versión del cliente como una columna binaria! ¡Tanto para proteger la integridad de la base de datos!

Manejo de Oracle de enlaces NULL:

http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/

http://jeffkemponoracle.com/2006/02/empty-string-andor-null.html

Cade Roux
fuente
1
valores inválidos de tiempo de datos? No estoy seguro de lo que eso significa. ¿Has publicado esto como una pregunta aquí?
1
El problema anterior a stackoverflow: no obtuve información útil de los foros de Oracle y creé una solución alternativa: rastrearé mis notas y las publicaré aquí.
Cade Roux
Detalles publicados como una pregunta aquí.
Cade Roux
-6

En primer lugar, las cadenas nulas y nulas no siempre fueron tratadas como iguales por Oracle. Una cadena nula es, por definición, una cadena que no contiene caracteres. Esto no es lo mismo que un nulo. NULL es, por definición, la ausencia de datos.

Hace cinco o seis años más o menos, la cadena nula fue tratada de manera diferente a nula por Oracle. Mientras que, como nulo, la cadena nula era igual a todo y diferente de todo (lo que creo que está bien para nulo, pero totalmente INCORRECTO para la cadena nula), al menos la longitud (cadena nula) devolvería 0, como debería ser ya que la cadena nula es Una cadena de longitud cero.

Actualmente en Oracle, la longitud (nulo) devuelve nulo, lo que supongo que está bien, pero la longitud (cadena nula) también devuelve nulo, lo cual es totalmente INCORRECTO.

No entiendo por qué decidieron comenzar a tratar estos 2 "valores" distintos de la misma manera. Significan cosas diferentes y el programador debe tener la capacidad de actuar sobre cada uno de diferentes maneras. El hecho de que hayan cambiado su metodología me dice que realmente no tienen idea de cómo deberían tratarse estos valores.

Michael T. Gunderson
fuente
Cita requerida para hacer una distinción entre "cadena nula" y valor NULO. En cualquier base de datos, excepto Oracle, un VARCHARcampo puede tener un valor (cero o más caracteres) o ningún valor (NULL), punto final.
"Hace cinco o seis años" a partir de 2011 caería en el marco de tiempo de 10 g (10.1 lanzado en 2003, 10.2 en 2005). 10g absolutamente no introdujo ningún cambio global en el manejo de nulos, y nunca ha habido ninguna distinción entre NULLuna cadena de valor nulo, y tal distinción no tiene sentido. Me temo que esta respuesta es una fantasía completa.
William Robertson