2008-10-15 27 views
192

Sé que hace considere '' como NULL, pero eso no hace mucho para decirme por qué este es el caso. Según entiendo las especificaciones de SQL, '' no es lo mismo que NULL - uno es un dato válido, y el otro indica la ausencia de esa misma información.¿Por qué Oracle 9i trata una cadena vacía como NULL?

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

+7

Siéntase libre de especular? De alguna manera, no creo que te 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. –

+0

http://docs.oracle.com/database/121/SQLRF/sql_elements005.htm#SQLRF51094 – Jayan

Respuesta

199

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

De vuelta en los viejos tiempos antes de que hubiera un estándar SQL, Oracle tomó la decisión de diseño que las cadenas vacías en VARCHAR/VARCHAR2 columnas eran NULL y que sólo había una sensación de NULL (hay teóricos relacionales que diferenciar entre los datos que nunca se haya solicitado, datos donde la respuesta existe, pero que el usuario no conoce, datos en los que no hay respuesta, etc., todos los cuales constituyen algún sentido de NULL).

En el momento en que apareció el estándar SQL y coincidió en que NULL y 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. Por lo tanto, 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 una cantidad potencialmente grande de consultas. Violar el estándar SQL (en mi humilde opinión) fue el menos perjudicial de estas tres opciones.

Oracle ha dejado abierta la posibilidad de que el tipo de datos VARCHAR iba a cambiar en una versión futura de adherirse al estándar SQL (razón por la cual todo el mundo utiliza VARCHAR2 en Oracle ya que el comportamiento de ese tipo de datos está garantizado para seguir siendo la misma en el futuro) .

-6

De hecho, he tenido nada pero las dificultades en el trato con Oracle, incluidos los valores de fecha y hora no válidos (no se pueden imprimir, convertido o nada, se limitó a la función dump()) que son permitió que se inserta en el base de datos, aparentemente a través de una versión con errores del cliente como una columna binaria! ¡Tanto para proteger la integridad de la base de datos!

manejo de Oracle de los nulos enlaces:

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

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

+1

¿valores de datatime no válidos? No estoy seguro de lo que eso significa. ¿Ha publicado esto como una pregunta aquí? –

+1

El problema anterior al stackoverflow problemático: no obtuve información útil de los foros de Oracle y creé una solución alternativa: rastrearé mis notas y las publicaré aquí. –

+0

Detalles publicados como una pregunta aquí. –

56

Tom Kyte VP de Oracle:

A varchar longitud cero se trata como NULL.

'' no se trata como NULO.

'' cuando se asigna a un char (1) se convierte en '' (tipos CHAR están en blanco acolchados cuerdas).

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

+15

Guau, Tom es bastante sarcástico. Dado que las preguntas se refieren a una divergencia atroz de SQL92, uno pensaría que sería menos contundente al respecto ... aunque podría estar cansado de responder. –

+7

Lo mejor de Tom es que obtienes una respuesta clara, que dice ** exactamente ** lo que piensa. Busque algunos de los comentarios donde las personas han usado texto para hablar en Ask Tom –

+8

Pero sería más preciso si la segunda línea se cambió a * '' no ** siempre ** se trata como NULL. * –

16

Oracle la documentación alerta a los desarrolladores sobre este problema, volviendo 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 ceros menos que resulten de los cálculos se convertirán 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 una 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 las usó.

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

18

Sospecho que esto tiene mucho más sentido si se piensa en la forma de Oracle desarrolladores anteriores probablemente hicieron - como un backend glorificado para un sistema de entrada de datos. Todos los campos de la base de datos correspondían a un campo en una forma que un operador de ingreso de datos veía en su pantalla. Si el operador no escribió nada en un campo, ya sea "fecha de nacimiento" o "dirección", 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 en realidad no tiene mucho sentido de todos modos.

+5

Eso solo tiene sentido si supone que todos los campos en un sistema de entrada de datos son obligatorios. Una 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 objetivo distinto de NULL. Incluso con esa suposición establecida, dudo que los primeros desarrolladores pensaran en Oracle como un "back up glorificado para un sistema de entrada de datos", así que no estoy seguro de que esta respuesta tenga sentido. – Jared

1

Porque no tratarlo como NULL tampoco es particularmente útil.

Si comete un error en esta área en Oracle, por lo general lo notará de inmediato. En el servidor SQL, sin embargo, parecerá que funciona, y el problema solo aparece cuando alguien ingresa una cadena vacía en lugar de NULL (quizás desde una biblioteca cliente .net, donde null es diferente de "", pero por lo general los trata de la misma manera)

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

+2

Mucho, mucho más fácil de depurar. Además, si ve una celda o entrada vacía en la pantalla, sabrá que los datos en el DB son nulos. En otros DBs donde '' <> NULL, no se puede "ver" si los datos son nulos o '', esto lleva a errores muy furtivos. '' = null es la opción más segura, incluso si no es estándar. –

+0

"En otros DB donde '' <> NULL, no puede" ver "si los datos son nulos o ''" => Por lo general, las herramientas de DB muestran NULL de forma diferente a las cadenas vacías. De hecho, incluso Oracle SQL Developer muestra NULLs 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. –

-5

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

Hace unos cinco o seis años, la cadena nula fue tratada de forma diferente a nula por Oracle. Mientras que, como null, string nulo era igual a todo y diferente de todo (que creo que está bien para nulo, pero totalmente INCORRECTO para cadena nula), al menos la longitud (cadena nula) devolvería 0, como debería ser, dado que una cadena de longitud cero.

Actualmente en Oracle, la longitud (nulo) devuelve nulo, lo que supongo que es O.K., 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. Significan cosas diferentes y el programador debe tener la capacidad de actuar en cada uno de diferentes maneras. El hecho de que hayan cambiado su metodología me dice que realmente no tienen ni idea de cómo deberían tratarse estos valores.

+0

Cita requerida para hacer una distinción entre "cadena nula" y valor NULL. En cualquier base de datos, excepto Oracle, un campo 'VARCHAR' puede tener un valor (cero o más caracteres) o ningún valor (NULL), punto final. –

3

Cadena vacía es lo mismo que NULO simplemente porque es el "mal menor" en comparación con la situación en la que los dos (cadena vacía y nulo) no son lo mismo.

En los idiomas donde NULL y cadena vacía no son lo mismo, siempre se deben verificar ambas condiciones.

+0

Simplemente configure la restricción 'not null' en su columna y verifique solo en una cadena vacía. –

+3

Comprobar 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. –

0

According to official 11g docs

base de datos Oracle actualmente trata un valor de carácter con una longitud de cero como nulo. Sin embargo, esto puede no continuar siendo cierto en versiones futuras, y Oracle recomienda que no trate las cadenas vacías lo mismo que las nulas.

razones posibles

  1. val IS NOT NULL es más legible que val != ''
  2. No hay necesidad de marcar ambas condiciones val != '' and val IS NOT NULL
+3

En una base de datos totalmente compatible con ANSI, no es necesario que verifique ambas condiciones. 'val <> ''' ya excluye 'NULL'. Tal vez quisiste decir 'val = '' O val IS IS NULL'. ¡Pero las cadenas vacías que no se pueden comparar como NULL son * útiles *! – ErikE

0

Ejemplo de 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; 
Cuestiones relacionadas