Te traemos el resultado a este rompecabezas, o por lo menos eso pensamos. Si sigues con alguna inquietud puedes escribirlo en el apartado de comentarios, para nosotros será un placer ayudarte
Solución:
Como señaló Phil, el vacío string se trata como NULL, y NULL no es igual o desigual a nada. Si espera cadenas vacías o NULL, deberá manejar aquellas con NVL()
:
DECLARE
str1 varchar2(4000);
str2 varchar2(4000);
BEGIN
str1:='';
str2:='sdd';
-- Provide an alternate null value that does not exist in your data:
IF(NVL(str1,'X') != NVL(str2,'Y')) THEN
dbms_output.put_line('The two strings are not equal');
END IF;
END;
/
Sobre null comparaciones:
De acuerdo con la documentación de Oracle 12c sobre NULLS, null comparaciones usando IS NULL
o IS NOT NULL
evaluar a TRUE
o FALSE
. Sin embargo, todas las demás comparaciones se evalúan como UNKNOWN
, noFALSE
. La documentación establece además:
Una condición que se evalúa como DESCONOCIDA actúa casi como FALSA. Por ejemplo, una declaración SELECT con una condición en la cláusula WHERE que se evalúa como DESCONOCIDA no devuelve filas. Sin embargo, una condición que se evalúe como DESCONOCIDA difiere de FALSO en que las operaciones posteriores en una evaluación de condición DESCONOCIDA se evaluarán como DESCONOCIDA. Por lo tanto, NO FALSO se evalúa como VERDADERO, pero NO DESCONOCIDO se evalúa como DESCONOCIDO.
Oracle proporciona una tabla de referencia:
Condition Value of A Evaluation
----------------------------------------
a IS NULL 10 FALSE
a IS NOT NULL 10 TRUE
a IS NULL NULL TRUE
a IS NOT NULL NULL FALSE
a = NULL 10 UNKNOWN
a != NULL 10 UNKNOWN
a = NULL NULL UNKNOWN
a != NULL NULL UNKNOWN
a = 10 NULL UNKNOWN
a != 10 NULL UNKNOWN
También aprendí que no debemos escribir PL/SQL asumiendo que las cadenas vacías siempre se evaluarán como NULL:
Oracle Database actualmente trata un valor de carácter con una longitud de cero como null. Sin embargo, esto no puede seguir siendo true en futuras versiones, y Oracle recomienda que no trate las cadenas vacías como si fueran nulos.
Completemos los espacios en su código, agregando las otras ramas en la lógica, y veamos qué sucede:
SQL> DECLARE
2 str1 varchar2(4000);
3 str2 varchar2(4000);
4 BEGIN
5 str1:='';
6 str2:='sdd';
7 IF(str1<>str2) THEN
8 dbms_output.put_line('The two strings is not equal');
9 ELSIF (str1=str2) THEN
10 dbms_output.put_line('The two strings are the same');
11 ELSE
12 dbms_output.put_line('Who knows?');
13 END IF;
14 END;
15 /
Who knows?
PL/SQL procedure successfully completed.
SQL>
Entonces, ¿las dos cadenas no son iguales ni no son iguales? ¿Eh?
Todo se reduce a esto. Oracle trata un vacío string como NULL. Si intentamos comparar un NULL y otro string el resultado no es VERDADERO ni FALSO, es NULO. Este sigue siendo el caso incluso si el otro string es también un NULL.
comparo cadenas usando =
y no <>
. He descubierto que en este contexto =
parece funcionar de manera más razonable que <>
. He especificado que dos cadenas vacías (o NULL) son iguales. La implementación real devuelve PL/SQL booleano, pero aquí lo cambié a pls_integer (0 es false y 1 es true) para poder demostrar fácilmente la función.
create or replace function is_equal(a in varchar2, b in varchar2)
return pls_integer as
begin
if a is null and b is null then
return 1;
end if;
if a = b then
return 1;
end if;
return 0;
end;
/
show errors
begin
/* Prints 0 */
dbms_output.put_line(is_equal('AAA', 'BBB'));
dbms_output.put_line(is_equal('AAA', null));
dbms_output.put_line(is_equal(null, 'BBB'));
dbms_output.put_line(is_equal('AAA', ''));
dbms_output.put_line(is_equal('', 'BBB'));
/* Prints 1 */
dbms_output.put_line(is_equal(null, null));
dbms_output.put_line(is_equal(null, ''));
dbms_output.put_line(is_equal('', ''));
dbms_output.put_line(is_equal('AAA', 'AAA'));
end;
/
Si haces scroll puedes encontrar los informes de otros desarrolladores, tú además tienes el poder insertar el tuyo si te apetece.