Oracle PL / SQL字符串比较问题

时间:2011-09-02 15:52:58

标签: sql oracle plsql oracle10g oracle11g

1)。你好,我有以下Oracle PL / SQL代码可能会因你们的观点而生锈:

 DECLARE
 str1  varchar2(4000);
 str2  varchar2(4000);
 BEGIN
   str1:='';
   str2:='sdd';
   IF(str1<>str2) THEN
    dbms_output.put_line('The two strings is not equal');
   END IF;
 END;
 /

很明显两个字符串str1和str2不相等,但为什么'两个字符串不相等'没有打印出来? Oracle有另一种比较两个字符串的常用方法吗?

7 个答案:

答案 0 :(得分:46)

正如Phil所说,空字符串被视为NULL,而NULL不等于或等于任何东西。如果您期望空字符串或NULL,则需要处理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;
 /

关于空比较:

根据Oracle 12c documentation on NULLS,使用IS NULLIS NOT NULL的空比较会评估为TRUEFALSE。但是,所有其他比较都评估为UNKNOWN FALSE。文件进一步指出:

  

评估为UNKNOWN的条件几乎就像FALSE。例如,在WHERE子句中具有计算结果为UNKNOWN的条件的SELECT语句不返回任何行。但是,评估为UNKNOWN的条件与FALSE的不同之处在于UNKNOWN条件评估的进一步操作将评估为UNKNOWN。因此,NOT FALSE计算结果为TRUE,但NOT UNKNOWN计算结果为UNKNOWN。

Oracle提供了一个参考表:

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

我还了解到我们不应该编写PL / SQL,假设空字符串总是计算为NULL:

  

Oracle数据库当前将长度为零的字符值视为null。但是,在将来的版本中可能不会继续这样,Oracle建议您不要将空字符串视为空值。

答案 1 :(得分:11)

让我们通过在逻辑中添加其他分支来填补代码中的空白,看看会发生什么:

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>

所以这两个字符串既不相同也不相同?咦?

归结为此。 Oracle将空字符串视为NULL。如果我们尝试比较NULL和另一个字符串,结果不是TRUE也不是FALSE,它是NULL。即使另一个字符串也是NULL,情况仍然如此。

答案 2 :(得分:2)

我使用=而不是<>来比较字符串。我发现在这种情况下,=似乎比<>更合理。我已指定两个空(或NULL)字符串相等。真正的实现返回PL / SQL布尔值,但在这里我将其更改为pls_integer(0为假,1为真),以便能够轻松演示该函数。

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;
/

答案 3 :(得分:1)

要解决核心问题,&#34;如果其中一个变量为空,我应该如何检测到这两个变量不具有相同的值?&#34;我不喜欢nvl(my_column, 'some value that will never, ever, ever appear in the data and I can be absolutely sure of that')的方法,因为您无法始终保证不会出现值...尤其是NUMBER。

我使用了以下内容:

if (str1 is null) <> (str2 is null) or str1 <> str2 then
  dbms_output.put_line('not equal');
end if;

免责声明:我不是Oracle向导,我自己想出了这个,并且没有在其他地方看到它,所以可能有一些微妙的原因,这是一个坏主意。但它确实避免了APC提到的陷阱,即将null与其他东西进行比较既不给出TRUE也不给出FALSE而是NULL。因为子句(str1 is null)将始终返回TRUE或FALSE,所以永远不会为null。

(注意PL / SQL执行短路评估,如here所述。)

答案 4 :(得分:0)

我为此文本比较目的创建了一个存储函数:

SELECT * FROM MyTable WHERE TextCompare(MyTable.a, '>=', MyTable.b) = 1;

例如:

def add_v4object(organization,v4object)

  @resource["/api/v1/#{organization}/v4address"].post(v4object, content_type: 'json')

答案 5 :(得分:0)

仅更改行 str1:=''; str1:='';

答案 6 :(得分:-5)

对第一个问题:

可能是因为您关闭了输出而没有打印出来的消息。使用这些命令将其重新打开:

set serveroutput on
exec dbms_output.enable(1000000);

关于第二个问题:

我的PLSQL非常生疏,所以我不能给你一个完整的片段,但你需要循环遍历SQL查询的结果集并将所有字符串CONCAT放在一起。