Oracle是否具有内置函数来从其各个组件(年,月和日)创建日期,该日期仅在缺失数据时返回false?
我知道TO_DATE()
但我需要先编写一个字符串,而||
运算符和CONCAT()
函数都不能轻松处理丢失的数据:
-- my_year NUMBER(4,0) NULL
SELECT TO_DATE(my_year || '-01-01', 'YYYY-MM-DD') AS my_date
FROM my_table;
每当my_year
为NULL
时,我们最终都会TO_DATE('-01-01', 'YYYY-MM-DD')
并且:
ORA-01841: (full) year must be between -4713 and +9999, and not be 0
答案 0 :(得分:5)
对于您的示例,您可以使用case
:
select (case when my_year is not null and my_year <> 0 and
my_year between -4713 and 9999
then TO_DATE(my_year || '-01-01', 'YYYY-MM-DD')
end)
不幸的是,如果可能的话,Oracle没有进行转换的方法,否则返回NULL。 SQL Server最近为此目的引入了try_convert()
。
一种选择是使用异常处理程序编写自己的函数以进行失败的转换。异常处理程序只会返回NULL
格式错误。
答案 1 :(得分:3)
您不能将{0}与to_date('0000-01-01', 'YYYY-MM-DD')
一起使用,但奇怪的是您可以使用日期文字date '0000-01-01'
。它本身就变成了第-1年,但你可以用它计算;并且您也可以添加一个间隔,该间隔可以基于您的数值,例如:
SELECT DATE '0000-01-01' + NUMTOYMINTERVAL(my_year, 'YEAR') AS my_date
FROM my_table;
如果参数为null,则numtoyminterval
function返回null,并将其添加到固定日期也会为null:
alter session set nls_date_format = 'SYYYY-MM-DD';
select date '0000-01-01' + numtoyminterval(null, 'YEAR') from dual;
DATE'0000-01-01'+NUMTOYMINTERVAL(NULL,'YEAR')
---------------------------------------------
select date '0000-01-01' + numtoyminterval(2015, 'YEAR') from dual;
DATE'0000-01-01'+NUMTOYMINTERVAL(2015,'YEAR')
---------------------------------------------
2015-01-01
select date '0000-01-01' + numtoyminterval(9999, 'YEAR') from dual;
DATE'0000-01-01'+NUMTOYMINTERVAL(9999,'YEAR')
---------------------------------------------
9999-01-01
select date '0000-01-01' + numtoyminterval(-4712, 'YEAR') from dual;
DATE'0000-01-01'+NUMTOYMINTERVAL(-4712,'YEAR')
----------------------------------------------
-4712-01-01
这不是万无一失的;如果你试图去-4713之前仍然会出错:
select date '0000-01-01' + numtoyminterval(-4713, 'YEAR') from dual;
SQL Error: ORA-01841: (full) year must be between -4713 and +9999, and not be 0
...
虽然您可以通过列上的检查约束来避免这种情况。并且由于第0年的静音转换为-1,如果my_year
值为0或-1,则会得到相同的答案:
select date '0000-01-01' + numtoyminterval(0, 'YEAR') from dual;
DATE'0000-01-01'+NUMTOYMINTERVAL(0,'YEAR')
------------------------------------------
-0001-01-01
select date '0000-01-01' + numtoyminterval(-1, 'YEAR') from dual;
DATE'0000-01-01'+NUMTOYMINTERVAL(-1,'YEAR')
-------------------------------------------
-0001-01-01
戈登·林诺夫的案例方法更加强大,但如果你真正处理“理智”的积极年份,这可能会奏效。如果没有,那就有点有趣......
答案 2 :(得分:0)
where my_year > 0
这将返回可以创建日期的行。忽略null或值为0的行。如果某些值不在-4713和+9999范围内,那么当然也应该在where子句中排除这些值。
答案 3 :(得分:0)
我最终组成了一个用户定义的函数来封装逻辑。它从其各个组成部分返回日期;如果日期无效,则返回NULL
:
CREATE OR REPLACE FUNCTION TRY_TO_DATE (
V_YEAR IN NUMBER,
V_MONTH IN NUMBER,
V_DAY IN NUMBER
) RETURN DATE DETERMINISTIC IS
BEGIN
RETURN TO_DATE(LPAD(V_YEAR, 4, '0') || LPAD(V_MONTH, 2, '0') || LPAD(V_DAY, 2, '0'), 'YYYY-MM-DD');
EXCEPTION
WHEN OTHERS THEN RETURN NULL;
END TRY_TO_DATE;
/