在SQL中,''和null之间有什么区别?
在SQL中,''和null之间有什么区别?
有两个简单的查询
--查询结果计数> 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')); --查询结果计数= 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'));
这两个查询之间唯一的区别是一个有空字符串(''),另一个有null。
我认为在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;
非常奇怪的是,上述两个查询返回相同的结果。但我仍然不确定,所以我尝试了另一个查询来确保''与null相同
还是不同。我尝试了以下两个查询:
select 1 from dual where '' is null; /*返回1条记录*/ select 1 from dual where '' is not null; /*返回0条记录*/
此时我感到非常困惑,现在我有以下问题
''等于null吗?
如果''等于null,那么为什么它不能与where条件一起使用?
请注意:我还尝试了>= <=代替between,但似乎还是不起作用。
我希望我的问题清楚明了,我没有漏掉任何内容。
在SQL中,''和null有什么区别?
在上述内容中,NVL()函数的文档说明了以下内容:
"expr1"和"expr2"参数可以是任何数据类型。如果它们的数据类型不同,Oracle数据库会隐式地将其中一个转换为另一个。
在第一个查询中,null不是一个已知的数据类型,因此无法隐式地转换第二个参数。在第二个查询中,''等同于null,但仍然是一个字符串表达式,所以日期也被隐式地转换为字符串。
当将"DateField"列与nvl()函数返回的字符串值进行比较时,字符串会被隐式地转换回日期。
所有这些隐式转换意味着您的NLS设置起到了作用。使用常见的NLS_DATE_FORMAT设置(如DD-MON-RR),由于RR的处理方式,没有日期匹配您的条件。
考虑以下示例:
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';
或者
select 1 from ordine where date '2000-01-01' <= DateField
and DateField <= date '1999-12-31';
这些条件不能同时为真,因此没有日期匹配。或者换句话说:
如果expr3 < expr2,则区间为空。
使用不同的NLS_DATE_FORMAT保留完整年份的情况下,您的第二个查询也将找到您期望的数据。
但是,不要依赖于NLS设置或隐式转换。当您需要表示null时,请使用null,而不是空字符串,即使它们通常被视为相同的。(Oracle建议您不要将空字符串视为null。)
我从来不擅长解释事物。综合而精确的答案。
''和null的区别在于在sql中的类型转换。''会自动转换为varchar类型,而null保持原有的数据类型。可以使用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;
解决方法:
要解决这个问题,可以根据需要使用不同的函数来处理空值和空字符串。如果需要将空值转换为特定的数据类型,可以使用nvl函数,如nvl(null, to_date('01/01/1900', 'dd/mm/yyyy'))。而如果需要将空字符串转换为特定的数据类型,可以使用to_date函数,如to_date('', 'dd/mm/yyyy')。通过选择合适的函数来处理空值和空字符串,可以避免类型转换的问题。
Oracle在处理空字符串时将其视为null,但只有在某些情况下将null视为空字符串。
select 'something' || '' from dual;
返回'something',但如果null不被视为空字符串,结果将返回null(表示未知的值,用null表示)。
请注意
select 1*NULL from dual;
返回预期的null值。
因此,您刚刚遇到了另一种出现这种不一致性的情况。NVL将''视为非空值(它是已知的,是空字符串),而在where条件中的IS NULL运算符却相反。这就是Oracle的特点...
编辑:重新编写 - 抱歉,刚刚加班...
你错了,你的示例结果将是something
。
是的,没错。如果在这种情况下将null视为空字符串,结果将会是null。大多数情况下,null只是null,并且对其应用运算符会导致null值。除了连接运算符...