2017-08-10 64 views
1

有2个简单的查询是什么之间的“差异”和空在SQL

--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')); 

只有这2个查询之间的区别在于,一个是具有空字符串(“”)等是有空。

我认为这可能是''不等于sql中的空值。所以我尝试以下查询:

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?
请注意:我也曾尝试> = < =代替之间和,但它似乎不起作用。

我希望我的问题很清楚,我不会错过任何东西。

+0

Oracle在大多数情况下内部将空字符串更改为空。请参阅:https://stackoverflow.com/questions/13278773/null-vs-empty-string-in-oracle – JBC

+0

''''和'NULL'是相同的 - 请参阅[为什么Oracle 9i将空字符串视为NULL? ](https://stackoverflow.com/q/203493/1509264)。 – MT0

+0

我不确定这是否真的是重复的,因为它确实在问为什么Oracle **不会在这种情况下将空字符串视为null。但也不确定是否打开它,并且可以整理出更真实的问题。 –

回答

0

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

select 'something' || '' 
from dual; 

回报“东西”,但如果NULL没有为空字符串处理,它会返回NULL作为其结果必然是未知(被表示为NULL)。

注意

select 1*NULL 
from dual; 

返回NULL预期。

所以你只是碰到另一种情况,出现这种不一致。 NVL认为'一个不为空值(它是已知的,它是空字符串),并在条件以另外一种方式way.That的甲骨文为你空操作...


编辑:改写正确 - 对不起,长班...

+0

你错了,你的抽样结果将是'something'。 – Seyran

+0

是的。如果在这种情况下NULL不被视为空字符串,它将会是NULL。大多数情况下,NULL只是NULL,并且它的运算符会导致NULL值。除了串接... – Igand

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

我认为这个问题不是那么有趣,它没有简单的答案。它来自没有足够的知识。如果你阅读Oracle有关空值,空值和字符串,函数中的空值以及比较中的空值的文档,则全部清楚。

+1

不是所有的问题都来自于没有足够的知识吗? (除了修辞性的......哦......)尽管问题的标题是关于空值,但它不是* *。 –

+0

无知和不愿意学习各种各样的东西,这个问题的作者应该简单地阅读15分钟的文档,一切都会清晰的 – Seyran

2

扩大对@ PonderStibbon的解释了一下,the documentation for the NVL() function说:

的参数表达式1和表达式2可以具有任何数据类型。如果它们的数据类型不同,那么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'); 

whic h仍然看起来应该在表面上起作用。但是现在是什么日子呢?使用您最初的日期和允许隐式转换,直到最后一刻,当我想看看在那里真的:

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

这些条件不能同时成立,所以没有日期匹配。或者换一种说法:

如果表达式3 <表达式2,则间隔为空


用不同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,即使它们通常被视为相同。 (Oracle recommends that you do not treat empty strings the same as nulls。)

+1

我从来没有擅长解释的东西;-)全面,准确的答案。 –

相关问题