Redshift can't convert a string to a date, tried multiple functions - sql

I have a table with a field called ADATE, it is a VARCHAR(16) and the values are like so: 2019-10-22-09:00.
I am trying to convert this do a DATE type but cannot get this to work.
I have tried:
1
TO_DATE(ADATE, 'YYYY-MM-DD')
Can't cast database type date to string
2
TO_DATE(LEFT(ADATE, 10), 'YYYY-MM-DD')
Can't cast database type date to string
3
TO_DATE(TRUNC(ADATE), 'YYYY-MM-DD')
XX000: Invalid digit, Value '-', Pos 4, Type: Decimal
4
CAST(ADATE AS DATE)
Error converting text to date
5
CAST(LEFT(ADATE, 10) AS DATE)
Error converting text to date
6
CAST(TRUNC(ADATE) AS DATE)
Error converting numeric to date

The issue was the data containing blanks (not Nulls) so the error was around them.
I resolved this by using the following code:
TO_DATE(LEFT(CASE WHEN adate = '' THEN NULL ELSE adate END, 10), 'YYYY-MM-DD') adate

Clearly, you have bad date string values -- which is why the value should be stored as a date to begin with.
I don't think Redshift has a way of validating the date before attempting the comparison, or of avoiding an error. But you can use case and regular expressions to see if the value is reasonable. This might help:
(case when left(adate, 10) ~ '^(19|20)[0-9][0-9]-[0-1][0-9]-[0-3][0-9]$'
then to_date(left(adate, 10), 'YYYY-MM-DD')
end)
This is not precise . . . you can make it more complex so month 19 is not permitted (for instance), but it is likely to catch the errors.

Related

Converting decimal to Date

I have a column with dates formatted as decimals, for example: 20,210,830.
I want to convert this number to date format as 08/30/2021
I have tried to use convert and the database shoots me an error that convert is not a valid function. Cast seems to work but, only returns a null value every time.
This statement will validate:
SELECT CAST(CAST(CONTCLMPDTE AS VARCHAR(8)) AS DATE)
FROM CMSFIL.JCTDSC AS COMPLDATE
This statement works but, just outputs null. For background I am querying from a Db2 database.
My ultimate goal is to use this converted date to grab the difference from the current day.
Such as
DAY(CURRENT_DATE) - DAY(COMPLDATE)
Converting it to a date, you cqan do it like this
CREATE TABLE JCTDSC (
CONTCLMPDTE varchar(10)
);
INSERT INTO JCTDSC VALUES ('20,220,830')
SELECT date(to_date(REPLACE(CONTCLMPDTE,',',''),'YYYYMMDD')) FROM JCTDSC AS COMPLDATE
1
2022-08-30
fiddle
So after a long couple days and almost pulling my hair out, here is what worked for me.
SELECT date(substr(CONTCLMPDTE,1,4)||'-'||substr(CONTCLMPDTE,5,2)||'-'||substr(CONTCLMPDTE,7,2)) FROM JCTDSC WHERE COMPANYNUMBER={Company Number} AND JOBNUMBER={Job Number} LIMIT 1
This formatted from yyyymmdd to mm/dd/yyyy. It also worked for finding the days between current_date and CONTCLMPDTE using this code.
DAYS(CURRENT_DATE) - DAYS({COntract Compl Date Formatted})
Thank you all for your help!
You probably get an error because you have some INT / DECIMAL value which can't be converted to a date using this pattern.
The solution is to create some "safe" conversion function "eating" errors like below.
CREATE FUNCTION DATE_SAFE (P_DT INT)
RETURNS DATE
CONTAINS SQL
NO EXTERNAL ACTION
DETERMINISTIC
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RETURN CAST (NULL AS DATE);
END;
RETURN DATE (TO_DATE (CAST (P_DT AS CHAR (8)), 'YYYYMMDD'));
END
Usage:
SELECT
CONTCLMPDTE
--, DATE (TO_DATE (CAST (CONTCLMPDTE AS CHAR (8)), 'YYYYMMDD'))
, DATE_SAFE (CONTCLMPDTE)
FROM (VALUES 0, 20220830) T (CONTCLMPDTE)
The function returns NULL if the corresponding INT can't be converted to a DATE, and no error is thrown as in case, when you uncomment the commented out line with built-in functions only.
The value just need to be converted into a string with a date format. Then you can use the date() function to convert to date.
create table qtemp/dec_vals (
col1 decimal(8,0) );
insert into qtemp/dec_vals
values (20200830), (20200831), (20200901), (20200902), (20200903), (20200904), (20200905), (20200906);
select date(substr(char(col1), 5, 2) || '/' || substr(char(col1), 7, 2) || '/' || substr(char(col1), 1, 4)) from qtemp/dec_vals;

Converting strings to date in SQL

I am using SQL Server 2017. I am trying to handle strings from a free format field and either convert them to a date in the format of "dd/mm/yyyy" or if they are not in this format then simply display the text verbatim.
I need this in a VIEW so can not use SET LANGUAGE. Sounds simple using Convert and IsDate but does not seem to work.
So for the snippet of code below (remember this will be in a view), I want to read the text and if the string converts to a date (ie. is in the format dd/mm/yyyy then run the convert to a date as I need it in date format for Excel to pick up (via Connect SQL Server database)), and if it does not convert to a date then display the text as it is.
create table dateTest1
(
idx int,
dateStringTest varchar(15)
);
insert into dateTest1 (idx, dateStringTest)
values (1, '13/01/2021'), (2, 'no');
select
case
when isdate(convert(datetime, dateStringTest, 103)) = 1
then convert(datetime, dateStringTest, 103)
else dateStringTest
end as dtres
from
dateTest1
--where idx = 1
Error:
Msg 241, Level 16, State 1, Line 15
Conversion failed when converting date and/or time from character string.
This error happens for idx = 2. Idx = 1 works ok.
Any assistance with this would be greatly appreciated. Thanks in advance.
You need to cast your resulting date to a varchar. A case expression can only return a single data type and the order-of-precedence means it is still trying to convert the varchar values to datetime
select
case when isdate( dateStringTest) = 1
then Cast(convert(datetime, dateStringTest, 103) as varchar(10))
else dateStringTest
end as dtres
from dateTest1
You can compact into a single statement (the same order of precedence applies)
select IsNull(Cast(Convert(datetime,Try_Cast(dateStringTest as date),103) as varchar(10)),dateStringTest)
from datetest1
Based on the syntax you are using, I assume you are using SQL Server. You should add the appropriate tag to your question.
The only way to do that in one column is to leave it as text.
Your use of ISDATE() is incorrect. If dateStringTest is not a valid date, CONVERT() on SQL Server will throw an error like:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
That's why you get an error for idx=2
You say you "need it in date format for Excel to pick up". How Excel interprets it will probably depend on your locale settings. Assuming mm/dd/yyyy is valid in your locale, Excel probably already sees it as a date. But I assume that's not happening, so mm/dd/yyyy is not valid for your locale. For me, if I have this table in SQL...
create table dateTest1 (
id int identity(1,1) not null,
dateStringTest varchar(20)
)
insert dateTest1
values
('2020-01-01')
, ('2020-21-01')
, ('2020-01-21')
, ('1/1/2020')
, ('1/21/2020')
, ('21/1/2020')
, ('21/01/2020')
, ('other stuff')
...and query it from Excel, adding columns with the functions DATEVALUE, DAY, WEEKDAY, and YEAR, I get...
id
dateStringTest
DATEVALUE
DAY
WEEKDAY
YEAR
1
2020-01-01
43831
1
4
2020
2
2020-21-01
#VALUE!
#VALUE!
#VALUE!
#VALUE!
3
2020-01-21
43851
21
3
2020
4
1/1/2020
43831
1
4
2020
5
1/21/2020
43851
21
3
2020
6
21/1/2020
#VALUE!
#VALUE!
#VALUE!
#VALUE!
7
21/01/2020
#VALUE!
#VALUE!
#VALUE!
#VALUE!
8
other stuff
#VALUE!
#VALUE!
#VALUE!
#VALUE!
That seems to indicate that Excel is recognizing some of the values as dates.
What you need to do is try to convert the value to datetime, then if it fails report the original value. In both cases, output a string.
You should review the documentation for CONVERT().
Try this:
select dateStringTest
, coalesce(cast(try_convert(datetime, dateStringTest, 103) as varchar(20)), dateStringTest) as dtres1
, coalesce(convert(varchar(20), try_convert(datetime, dateStringTest, 103), 103), dateStringTest) as dtres2
, coalesce(convert(varchar(20), try_convert(datetime, dateStringTest, 103), 101), dateStringTest) as dtres3
from dateTest1
UPDATE
If you are considering only values matching the pattern dd/mm/yyyy as dates (so 17/01/2021 is a date and 17/1/2021 is not), this brute force method will work with SQL Server 2008 (compatibility level 100):
(Notice I updated my input, also, above.)
;
with a as (
select id
, dateStringTest
, SUBSTRING(dateStringTest, 7, 4) + '-' + SUBSTRING(dateStringTest, 4, 2) + '-' + SUBSTRING(dateStringTest, 1, 2) as converteDate
from dateTest1
)
select id
, cast(convert(datetime, dateStringTest, 103) as varchar(20)) as dtres
from a
where isdate(converteDate) = 1
union
select id
, dateStringTest as dtres
from a
where isdate(converteDate) = 0

SQl Server Converting to Date fails , DateTime works

I have a table with a varchar(25) column that holds a date value. A typical value is '11/04/2017'.
This query returns 0 rows
select *
from myTable
where isdate(inputDate) = 0
I am trying to find a max on this, using a date sort.
This query returns the expected result
;with gooddates as
(
select
medcomfolder, PatientId, PatientBirthday, InputDate
from
myTable
where
isdate(inputDate) = 1
)
select max(convert(datetime, inputDate))
from gooddates
This query returns an error.
;with gooddates as
(
select
medcomfolder, PatientId, PatientBirthday, InputDate
from
dwhFuData
where
isdate(inputdate) = 1
)
select max(convert(date, inputdate))
from gooddates
This is the returned error
Msg 241, Level 16, State 1, Line 274
Conversion failed when converting date and/or time from character string
The difference between the 2 queries is that the first is converting to a dateTime while the latter is converting to a date.
At this point, I can move forward w/ the dateTime option, but I am left wondering what I am missing.
I have checked that there are no embedded spaces, and all the columns have a len(InputDate) = 10 (there is NO time data included)
I selected distinct values,put them in excel, and did a date function on each row. I was hoping to get a #VALUE on 1 row. All the rows worked.
So there is nothing silly like '02/31/2019' going on.
How can a dateTime conversion pass when a simple date conversion does not?
My guess is that you have values that include a time stamp following the date (based on the fact that isdate() is always zero).
If so, one simple solution would be to use convert(date, left(inputdate, 10)). Another solution uses try_convert():
try_convert(date, inputdate)
To find the offending values:
select inputdate
from dwhFuData
where try_convert(date, inputdate) is null and inputdate is not null;

Invalid data error in Redshift

I have a query I am running in redshift that produces an error when I try to compare two dates. I have determined this is due to a data problem where the dates are VARCHAR and some are empty strings. The best solution is clearly to fix this at the source, but while trying to build a work around, I stumbled upon some very odd behavior.
To get around, I preselect the dates that are not empty strings, and cast as dates, then convert to integer date format (YYYYMMDD) and convert to INT. This runs fine. However, if I try to compare this with an integer in a WHERE clause, the query crashes with a data type error.
Here is a toy version of the working query
SELECT
date_id,
COUNT(*)
FROM
(
SELECT
CONVERT(int, date_id) AS date_id
FROM
(
SELECT
DATE_PART('year', start_dttm)*10000+DATE_PART('month', start_dttm)*10+DATE_PART('day', start_dttm) AS date_id
FROM
(
SELECT
CAST(start_dttm AS DATETIME) AS start_dttm
FROM
sfe.calendar_detail
WHERE
start_dttm <> ''
) cda
) cdb
) cd
GROUP BY
date_id
;
And here is the failed query
SELECT
date_id,
COUNT(*)
FROM
(
SELECT
CONVERT(int, date_id) AS date_id
FROM
(
SELECT
DATE_PART('year', start_dttm)*10000+DATE_PART('month', start_dttm)*10+DATE_PART('day', start_dttm) AS date_id
FROM
(
SELECT
CAST(start_dttm AS DATETIME) AS start_dttm
FROM
sfe.calendar_detail
WHERE
start_dttm <> ''
) cda
) cdb
) cd
WHERE
date_id >= 20170920
GROUP BY
date_id
;
As I mentioned above, the correct solution is to fix the data type and count empty dates as Nulls not empty strings, but I am very curious as to why the second query crashes on an invalid data type error.
Many Thanks!
Edit:
Here is the error
ERROR: Invalid digit, Value '1', Pos 0, Type: Integer
DETAIL:
-----------------------------------------------
error: Invalid digit, Value '1', Pos 0, Type: Integer
code: 1207
context:
query: 2006739
location: :0
process: query0_39 [pid=0]
-----------------------------------------------
Rather than converting dates to the human-readable YYYYMMDD format, it is always better to keep them as DATE or TIMESTAMP format. This way, date operations can be easily performed (eg adding 5 days to a date). You can still do easy comparison operators by using 'YYYYMMDD'::DATE.
Given that you are converting from a String, and casting to a Date seems to work, and that you have some empty strings, use this to convert it to a date:
SELECT
NULLIF(start_dttm, '')::DATE AS dt
FROM sfe.calendar_detail
WHERE dt > '20170920'::DATE
This will return a NULL if the string is empty, and a Date if it contains a date that could be converted.

Converting a numeric value to date time

I am working in SQL Server 2012. My date column in a data set looks like this: 41547. The column is in nvarchar (255). I want to convert it to something like this: yyyy-mm-dd hh:mm:ss (Example: 2013-09-14 12:23:23.98933090). But I can not do this. I am using following code:
select convert(datetime, date_column, 6)
But this is giving following error:
Msg 241, Level 16, State 1, Line 1 Conversion failed when converting
date and/or time from character string.
What am I doing wrong?
Your date is actually a numeric value (float or integer), stored in a char column. So, you need to convert it to a numerical value (in this case, to float) first, like:
select convert(datetime, CONVERT(float,date_column))
A value of 41547.5 will result in:
`2013-10-02 12:00:00`
The style argument, in your case 6 is only necessary when converting from or to char-types. In this case it is not needed and will be ignored.
NB: The float value is the number of days since 1900-01-01.
e.g. select convert(datetime, CONVERT(float,9.0)) => 1900-01-10 00:00:00; the same as select dateadd(day,9.0,'1900-01-01') would.
The decimal part of the number also equates to days; so 0.5 is half a day / 12 hours.
e.g. select convert(datetime, CONVERT(float,.5)) => 1900-01-01 12:00:00. (Here our comparison to dateadd doesn't make sense, since that only deals with integers rather than floats).
There is an easier way to do it as well.
select convert(date,cast (date_Column+ 19000000 as nvarchar(10)))
as date_Column_Formated
from table_Name
I have just found the way to do this.
First I have to covert the nvarchar to int then I have to convert it to date time. I have used following code:
Select convert(datetime, (convert (int, [date_column])), 6) as 'convertedDateTime' from mytable
6 format is: "dd mon yy"
Like this: SELECT convert(datetime, '23 OCT 16', 6)
Other formats will cause your error
SELECT CONVERT(DATETIME,CONVERT(INT,date_column))