sql中''和null之间有什么区别?

时间:2017-08-10 14:36:47

标签: sql oracle

有2个简单的查询

--Query returns results count > 0
select 1 from ordine where DateField between nvl(null, to_date('01/01/1900', 'dd/mm/yyyy')) and nvl(null, to_date('31/12/2999', 'dd/mm/yyyy'));

--Query returns results count = 0
select 1 from ordine where DateField between nvl('', to_date('01/01/1900', 'dd/mm/yyyy')) and nvl('', to_date('31/12/2999', 'dd/mm/yyyy'));

这两个查询之间的唯一区别是One有空字符串('')而其他查询有空。

我认为可能''在sql中不等于null。所以我尝试了以下查询:

select  nvl(null, to_date('01/01/1900', 'dd/mm/yyyy')), nvl(null, to_date('31/12/2999', 'dd/mm/yyyy')) from dual;

select  nvl('', to_date('01/01/1900', 'dd/mm/yyyy')), nvl('', to_date('31/12/2999', 'dd/mm/yyyy')) from dual;

上述两个查询都返回了相同的结果,这很奇怪。但我仍然不确定,所以我尝试了另一个查询以确保'' is same as null。我尝试了2个查询:

select  1 from dual where '' is null; /* returned 1 record*/
select  1 from dual where '' is not null; /* returned 0 records*/

此时我很困惑,现在我有以下问题 是'' equal to null?
if '' equal to null then why it doesn't work with where conditions?
请注意:我也试过> =< =而不是和之间,但是它似乎无法正常工作。

我希望我的问题很明确,我不会遗漏任何内容。

4 个答案:

答案 0 :(得分:3)

因为nvl('', to_date('01/01/1900', 'dd/mm/yyyy'))自动转换为varchar而nvl(null, to_date('01/01/1900', 'dd/mm/yyyy'))是日期类型。

您可以使用dump

进行检查
select dump(nvl('', to_date('01/01/1900', 'dd/mm/yyyy'))) from dual;

select dump(nvl(null, to_date('01/01/1900', 'dd/mm/yyyy'))) from dual;

答案 1 :(得分:2)

稍微扩展@ PonderStibbon的解释,the documentation for the NVL() function说:

  

参数expr1和expr2可以包含任何数据类型。如果它们的数据类型不同,则Oracle数据库会隐式地将其中一个转换为另一个。

在您的第一个查询中,null不是已识别的数据类型,因此第二个参数无法隐式转换。在第二个查询中,''等效于null但仍然是字符串表达式,因此日期也会隐式转换为字符串,如转储显示。

DateField列与nvl() the string is implicitly converted back to a date返回的字符串值进行比较时。

所有这些隐式转换意味着您的NLS设置发挥作用。使用NLS_DATE_FORMAT之类的常见DD-MON-RR设置,因为how RR is handled,所以没有日期符合您的条件。

考虑:

select nvl('', to_date('01/01/1900', 'dd/mm/yyyy')),
  nvl('', to_date('31/12/2999', 'dd/mm/yyyy'))
from dual;

NVL('',TO NVL('',TO
--------- ---------
01-JAN-00 31-DEC-99

请记住这些是字符串,而不是日期。如果您在与实际日期进行比较时使用它们会发生什么?

select * from dual
where date '2017-01-01' between nvl('', to_date('01/01/1900', 'dd/mm/yyyy'))
  and nvl('', to_date('31/12/2999', 'dd/mm/yyyy'));

这是真的,因为他们评估为字符串:

select * from dual
where date '2017-01-01' between '01-JAN-00' and '31-DEC-99';

但是他们将这些字符串隐式转换回日期:

select * from dual
where date '2017-01-01' between to_date('01-JAN-00') and to_date('31-DEC-99');

使用相同的NLS设置:

select * from dual
where date '2017-01-01' between to_date('01-JAN-00', 'DD-MON-RR')
  and to_date('31-DEC-99', 'DD-MON-RR');
表面上仍然看起来应该可以工作的

。但现在这些日期是什么呢?使用您的初始日期并允许隐式转换直到最后一刻,当我想知道那里的真实情况时:

select to_char(to_date(to_char(to_date('01/01/1900', 'dd/mm/yyyy'))), 'SYYYY-MM-DD'),
  to_char(to_date(to_char(to_date('31/12/2999', 'dd/mm/yyyy'))), 'SYYYY-MM-DD') from dual;

TO_CHAR(TO_ TO_CHAR(TO_
----------- -----------
 2000-01-01  1999-12-31

RR规则意味着两位数年份00转换为2000年,而两位数年份99年转换为1999年。

所以你的第二个查询实际上是这样做的:

select 1 from ordine where DateField between date '2000-01-01' and date '1999-12-31';

or

select 1 from ordine where date '2000-01-01' <= DateField
  and DateField <= date '1999-12-31';

并且这些条件不能同时为真,因此没有日期匹配。或者换句话说:

  

如果expr3&lt; expr2,则间隔为空

使用保留全年的其他NLS_DATE_FORMAT,您的第二个查询也会找到您期望的数据:

alter session set nls_date_format = 'DD-MON-RR';

select 1 from dual where sysdate between nvl('', to_date('01/01/1900', 'dd/mm/yyyy')) and nvl('', to_date('31/12/2999', 'dd/mm/yyyy'));

no rows selected

alter session set nls_date_format = 'SYYYY-MM-DD';

select 1 from dual where sysdate between nvl('', to_date('01/01/1900', 'dd/mm/yyyy')) and nvl('', to_date('31/12/2999', 'dd/mm/yyyy'));

         1
----------
         1

但不要依赖NLS设置或隐式转换。当你的意思是null时使用null,而不是空字符串,即使它们通常被视为相同。 (Oracle recommends that you do not treat empty strings the same as nulls。)

答案 2 :(得分:0)

Oracle将空字符串视为null,但有时仅将NULL视为空字符串。

select 'something' || '' 
from dual;

返回&#39;某些内容&#39;,但如果NULL未被视为空字符串,则返回NULL,因为结果将是未知的(表示为NULL)。

请注意

select 1*NULL
from dual;

按预期返回NULL。

所以你只是碰到另一个出现这种不一致的情况。 NVL认为&#39;&#39;一个非空值(它是已知的,它是空字符串)和IS NULL运算符,其中条件是另一种方式。那对你的甲骨文...

编辑:正确改写 - 抱歉,长途转移......

答案 3 :(得分:-2)

我认为问题不是那么有趣,也没有简短的回答。它来自于没有足够的知识。如果您阅读有关空值,空值和字符串的Oracle文档,函数中的空值以及比较中的空值,则所有内容都将清楚。