扩大对@ 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。)
Oracle在大多数情况下内部将空字符串更改为空。请参阅:https://stackoverflow.com/questions/13278773/null-vs-empty-string-in-oracle – JBC
''''和'NULL'是相同的 - 请参阅[为什么Oracle 9i将空字符串视为NULL? ](https://stackoverflow.com/q/203493/1509264)。 – MT0
我不确定这是否真的是重复的,因为它确实在问为什么Oracle **不会在这种情况下将空字符串视为null。但也不确定是否打开它,并且可以整理出更真实的问题。 –