Verify Data Type Conversions: 12 Things Developers Will Love About Oracle Database 12c Release 2 Part 7

Chris Saxon
Oracle Developers
Published in
3 min readNov 10, 2016

It’s one of those all too common problems. Validating a date is indeed a date.

A prime cause of this is the terrible practice of storing dates as strings. One of the biggest issues it is enables people to store things that clearly aren’t dates in “date” columns:

create table dodgy_dates ( 
id int,
is_this_a_date varchar2(20)
);
insert into dodgy_dates values (1, 'abc');

Along with a whole bunch of values that might be dates. If you supply the correct format mask:

insert into dodgy_dates values (2, '20150101'); 
insert into dodgy_dates values (3, '01-jan-2016');
insert into dodgy_dates values (4, '01/01/2016');

Returning only the valid dates is tricky. If you try to convert everything using to_date(), you’ll get exceptions:

select t.* from dodgy_dates t 
where to_date(is_this_a_date) < sysdate;
ORA-01858: a non-numeric character was found where a numeric was expected

or maybe:

ORA-01861: literal does not match format string

or

ORA-01843: not a valid month

You could get around this by writing your own is_date() function. Or, if you’re really brave, use a regular expression.

Either way, it’s a lot of unnecessary work.

So to make your life easier, we’ve created a new function, validate_conversion. You pass this a value and a data type. Then Oracle Database will tell you whether it can do the conversion. If it can, it returns one. Otherwise you get zero.

To return the rows in the table that can be real dates, place this in your where clause:

select t.* from dodgy_dates t 
where validate_conversion(is_this_a_date as date) = 1;
ID IS_THIS_A_DATE
---------- --------------------
3 01-jan-2016

There’s no error. But where did rows 2 and 4 go? They’re possible dates too!

Validate_conversion only tests one date format at a time. By default this is your NLS_date_format

Each client can set their own format. So if you rely on this, you may get unexpected results…

To avoid this, I strongly recommend you pass the format as a parameter. For example:

select t.* from dodgy_dates t 
where validate_conversion(is_this_a_date as date, 'yyyymmdd') = 1;
ID IS_THIS_A_DATE
---------- --------------------
2 20150101

So to return all the possible dates, you’ll need to call this multiple times:

select t.* from dodgy_dates t 
where validate_conversion(is_this_a_date as date, 'yyyymmdd') = 1 or
validate_conversion(is_this_a_date as date, 'dd/mm/yyyy') = 1 or
validate_conversion(is_this_a_date as date, 'dd-mon-yyyy') = 1;
ID IS_THIS_A_DATE
---------- --------------------
2 20150101
3 01-jan-2016
4 01/01/2016

And this isn’t just for dates. You can use validate_conversion with any of the following data types:

  • binary_double
  • binary_float
  • date
  • interval day to second
  • interval year to month
  • number
  • timestamp
  • timestamp with time zone

If you want to convert strings to dates, you’ll need similar logic in the select. This will test the expression against various format masks. If it matches, call to_date with the relevant mask:

case 
when
validate_conversion(is_this_a_date as date, 'yyyymmdd') = 1
then to_date(is_this_a_date, 'yyyymmdd')
when
validate_conversion(is_this_a_date as date, 'dd/mm/yyyy') = 1
then to_date(is_this_a_date, 'dd/mm/yyyy')
when
validate_conversion(is_this_a_date as date, 'dd-mon-yyyy') = 1
then to_date(is_this_a_date, 'dd-mon-yyyy')
end

Full article originally published at blogs.oracle.com on November 10, 2016.

--

--

Chris Saxon
Oracle Developers

I’m Chris Saxon, an Oracle Developer Advocate for SQL. My job is to help you get the best out of the Oracle Database and have fun with SQL!