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
答案 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'