Converting strings to date in SQL - 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

Related

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

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.

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;

Convert VARCHAR to DATE in SQL SERVER

I have VARCHAR column (MyValue) in my table. It has date value in two different format.
MyValue
----------
25-10-2016
2016-10-13
I would like to show them in DATE format.
I wrote query like below:
SELECT CONVERT(date, MyValue, 105) FROM MyTable
SELECT CAST(MyValue as date) FROM MyTable
Both are giving me this error. Conversion failed when converting date and/or time from character string.
Is there anyway convert to DATE datatype format even the value stored in different formats like above?
Expecting your answers. Thanks in advance.
Does this help?
declare #varchardates table
(
vcdate varchar(20)
)
INSERT INTO #varchardates VALUES
('25-10-2016'),
('2016-10-13')
SELECT CONVERT(date,vcdate, case when SUBSTRING(vcdate, 3, 1) = '-'
THEN 105 ELSE 126 END) as mydate
FROM #varchardates
Depending on how many different formats you have in your data, you may need to extend the case statement!
See here for list of the different format numbers
You can use TRY_CONVERT and COALESCE. TRY_CONVERT returns NULL if the conversion fails, COALESCE returns the first NOT NULL value:
SELECT COALESCE(TRY_CONVERT(DATETIME, x, 105), TRY_CONVERT(DATETIME, x, 120))
FROM (VALUES('25-10-2016'), ('2016-10-13')) a(x)
I assumed the value 2016-10-13 is in format yyyy-MM-dd.
You mention in a comment you may have other formats as well. In that case it gets very tricky. If you get a value 01-12-2017 and you have no idea about the format, there is no way to tell whether this is a date in januari or in december.

Function to evaluate valid and invalid dates

I am using SQL Server 2008
I receive data in a couple of formats. Dates are varchar(10)
For example:
1> 951116 = YYMMDD
2> 122487 = MMDDYY
There exists rows with blank values or some rows have some text in it.
I want to check if it is a date and convert it, else it can be null.
I have been using the following code but it only enables me to convert the date as in the 1st example and throws an error in the second one.
create view v2 as
SELECT name
,CASE WHEN LEN(DOB) < 6 THEN '' ELSE CONVERT(VARCHAR,
CAST(CAST('19' + SUBSTRING(DOB, 5, 2) + SUBSTRING(DOB, 1, 2) + SUBSTRING(DOB, 3, 2) AS VARCHAR(10)) AS DATE), 110) END AS OWNR_DOB
FROM customer
I want to write a function and get it to YYYYMMDD format.
A simple function just to convert the YYMMDD format to YYYYMMDD and treat the other values as invalid or null can be a start too.
Any help is appreciated.

Pull numbers out of a decimal

Okay so, I have a column that looks something like this:
20140813000000000
It is displaying a date, in the format of decimal(17,0), but I need to take the first 8 characters out of it to convert it to a date so it can be used. I've tried casting and converting and substring but everything leads to an arithmetic overflow. Any help on getting that date out?
Example of what I am using and the error:
CAST(SUBSTRING(CAST([tblDate] as varchar),1,8) as Date)
Conversion failed when converting date and/or time from character string.
I got it working, I added a case to filter out the 0's to NULL before casting it as a date:
Select
CAST(CASE
WHEN SUBSTRING(CAST([tblDate] as varchar),1,8) = 0 THEN NULL
ELSE SUBSTRING(CAST([tblDate] as varchar),1,8)
END as DATE)
Great that you found a solution to your own problem, but note that this won't work if you ever have values like 00000000000000001 in your table as this will be converted to 1, pass the first test in your CASE statement and then throw an exception as 1 won't CAST to DATE.
This is more long-winded, but safer... (full example included):
DECLARE #TestTable TABLE ([tblDate] NUMERIC(17,0));
INSERT INTO #TestTable VALUES(00000000000000001); --Edge case
INSERT INTO #TestTable VALUES(20140831000000001); --Value to parse
SELECT
CASE
WHEN SUBSTRING(REPLACE(RIGHT('00000000000000000' + CAST([tblDate] AS VARCHAR(17)), 17), SPACE(1), '0'), 1, 8) = '00000000' THEN NULL
ELSE SUBSTRING(CAST([tblDate] AS VARCHAR(17)), 1, 8)
END
FROM
#TestTable;
Returns:
NULL
2014-08-31
Your answer would throw an exception for the first value.
If you are sure your data will ALWAYS either be all zeroes or contain a date to be parsed then fine...