为什么在传递空格时,ORACLE TO_DATE函数在OR条件下没有给出ORA-01841错误?

时间:2018-12-19 06:43:15

标签: sql oracle to-date

SQL> select to_date('    ','YYYYMMDD') from dual;
ERROR at line 1:
ORA-01841: (full) year must be between -4713 and +9999, not be 0

SQL> select * from dual where to_date('    ','YYYYMMDD') = '19960512' or 1 = 2;
ERROR at line 1:
ORA-01841: (full) year must be between -4713 and +9999, not be 0

SQL> select * from dual where to_date('    ','YYYYMMDD') = '19960512' or 1 = 1;
Success.

在前两个语句中,我们将空格传递给TO_DATE函数,该函数会产生预期的错误。 但是

现在在第三条语句中,我们将空格传递到TO_DATE oracle函数,这是不允许的。但是它仍然可以成功执行。

为什么?

在实际代码中,我可能会传递变量中的空格,而OR部分可能为true,也可能为非。

任何人都可以向我解释此行为以及如何处理以获取错误吗?

PS-我正在使用Oracle 12g EE

3 个答案:

答案 0 :(得分:4)

Oracle在这里使用短路逻辑。由于已知1=1是真实的,因此Oracle优化了对其他条件的评估。由于从未对其进行评估,因此将无效参数传递给它的事实是无关紧要的。

答案 1 :(得分:3)

另一个答案没有解决您仍然希望得到错误的部分问题

我建议您单独进行日期解析。如果这是一个存储过程,请不要像在此处那样放置查询,创建一个日期变量,使用to_date为其分配一个日期值(如果用户提供空格,它将崩溃),然后使用date变量在查询中。这样,即使给出了错误的数据,Oracle仍然有机会扼杀它。

或者使您的存储过程采用日期类型参数而不是字符串,以强制调用程序提供合理且一致的日期

答案 2 :(得分:1)

您可以在or分支中重复进行转换,这显然有点混乱:

select * from dual
where to_date('    ','YYYYMMDD') = '19960512'
or (1 = 1 and to_date('    ','YYYYMMDD') != '19960512');

Error report -
ORA-01841: (full) year must be between -4713 and +9999, and not be 0

或者,如果您唯一需要担心的无效日期方案是空格,则可以采取其他措施使该分支在这种情况下的值为false:

select * from dual
where to_date('    ','YYYYMMDD') = '19960512'
or (1 = 1 and trim('    ') is not null);
  从数据库中获取

字符串并在查询中传递给TO_DATE

表示您将日期作为字符串存储在数据库which is not a good idea中;因此,如果您在那里可以有空间,那么您将有任何东西,并且也必须处理其他潜在错误,而is not null方法将无法解决。

这些查询都不会因传入空字符串(即null)而出错-但是您的前两个原始查询也不会;他们都将找不到数据。


当然,'19960512'不是日期,因此您要在此处进行其他隐式转换。也可以更安全地通过to_date()传递它,或者如果它确实是固定值,则使用日期文字:

where to_date('    ','YYYYMMDD') = date '1996-05-12'