Create date from year, month and day

。_饼干妹妹 提交于 2019-12-23 16:41:22

问题


Does Oracle have a builtin function to create a date from its individual components (year, month and day) that just returns false on missing data?

I'm aware of TO_DATE() but I need to compose a string first and neither the || operator nor the CONCAT() function make it easy to handle missing data:

-- my_year NUMBER(4,0) NULL
SELECT TO_DATE(my_year || '-01-01', 'YYYY-MM-DD') AS my_date
FROM my_table;

Whenever my_year is NULL we end up with TO_DATE('-01-01', 'YYYY-MM-DD') and:

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

回答1:


For your example, you can use 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)

Unfortunately, Oracle does not have a method of doing the conversion, if possible, and otherwise returning NULL. SQL Server recently introduced try_convert() for this purpose.

One option is to write your own function with an exception handler for the failed conversion. The exception handler would simply return NULL for a bad format.




回答2:


You can't use year zero with to_date('0000-01-01', 'YYYY-MM-DD'), but oddly you can with a date literal date '0000-01-01'. On its own that becomes year -1, but you can use it calculations; and you can add an interval too which can be based on your numeric value, e.g.:

SELECT DATE '0000-01-01' + NUMTOYMINTERVAL(my_year, 'YEAR') AS my_date
FROM my_table;

The numtoyminterval function returns null if the argument is null, and adding that to a fixed date also gives you 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                                   

It isn't foolproof; it will still error if you try to go before -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
...

Though you can avoid that with a check constraint on the column. And because of the silent translation of year 0 to -1, you get the same answer if your my_year value is 0 or -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                                

Gordon Linoff's case approach is more robust, but this might work if you're only really dealing with 'sane' positive years. And if not, it's mildly interesting...




回答3:


where my_year > 0

This will just return rows where it's possible to create a date. Ignoring rows with null or with a value of 0. If you have some values not in the range -4713 and +9999, you should of course exclude those in the where clause too.



来源:https://stackoverflow.com/questions/31538180/create-date-from-year-month-and-day

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!