Issue in using TRY_PARSE in CASE WHEN Statement - sql

I need to validate the dates with different formats like
Thursday March 15, 2018, 05-21-1995, 04.03.1934 and I may get Invalid Dates like N/A, #### etc.,. I am using the Following Query to validate the date in Stored procedure, here I insert the date into the date column and set Error Flag If there is an Invalid date.
INSERT INTO table_name(date_column,date_error)
SELECT
CASE WHEN TRY_PARSE(date_column AS datetime USING 'en-US') is NULL THEN date_column
ELSE TRY_PARSE(date_column AS datetime USING 'en-US')
END as date_column,
CASE WHEN TRY_PARSE(date_column AS datetime USING 'en-US') is NULL THEN 1
ELSE 0
END as date_error
FROM #temp_table;
I'm getting the Error as Conversion failed when converting date and/or time from character string for date value ####.

You cannot put two different types in one column
This may work for you
declare #T table (pk int identity primary key, varDt varchar(100));
insert into #T (varDt) values ('Thursday March 15, 2018'), ('05-21-1995'), ('N/A'), ('####'), ('easter'), ('');
declare #Tf table (pk int primary key, varDt varchar(100), needFix bit, dt datetime);
insert into #Tf
select t.pk, t.varDt
, case when TRY_PARSE(t.varDt AS datetime USING 'en-US') is null then 1 else 0 end as needFix
, TRY_PARSE(t.varDt AS datetime USING 'en-US') as dt
from #T t;
select *
from #Tf tf
order by needFix desc, pk;

Thanks for all your comments. As #gordon-linoff said we can't have two different datatypes in CASE WHEN Statement. So, I CAST the else statement to varchar.
INSERT INTO table_name(date_column,date_error)
SELECT
CASE WHEN TRY_PARSE(date_column AS datetime USING 'en-US') is NULL THEN date_column
ELSE CAST(TRY_PARSE(date_column AS datetime USING 'en-US') AS varchar(max))
END as date_column,
CASE WHEN TRY_PARSE(date_column AS datetime USING 'en-US') is NULL THEN 1
ELSE 0
END as date_error
FROM #temp_table;

Related

Cast to datetime only if its a date value

I have a table with DateFrom column
it's an nvarchar col in the col I have data like that
01
02
10/10/2020
04
some strings and some DateTime values
I need to cast it to DateTime but only if it's a date if not then pull out the value like it is can is this possible?
thanks ...
a Simple Try cast should do the job here
DECLARE #Table TABLE (Val NVARCHAR(20))
INSERT INTO #Table
VALUES('1'),('2'),('10/10/2020'),('04')
SELECT
*,
TRY_CAST(Val AS DATE)
FROM #Table
Results
Something like this should work. It uses a CASE statement to check whether or not the value is a valid date and if so casts it to DATETIME, then converts it to VARCHAR (so dates and other values can be returned as the same column).
You can find other datetime to string styles here if you need them formatted differently:
https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver15
DECLARE #TempTable TABLE (Dt NVARCHAR(30))
INSERT INTO #TempTable
VALUES('1'),('2'),('10/10/2020'),('04'),('Jun 27 2021 12:22AM'),('Oct 12 2021 8:31PM')
SELECT
*,
CASE WHEN ISDATE(Dt) = 1 THEN Convert(VARCHAR, CAST(Dt AS DATETIME), 120) ELSE Dt END
FROM #TempTable
You can easily check this with the case statement.
Postgres example
select case when '12/12/2021' ~ '\d{2}\/\d{2}\/\d{4}' then 'this is the date' ELSE 'this is a string' end;
->this is the date
select case when 'some text' ~ '\d{2}\/\d{2}\/\d{4}' then 'this is the date' ELSE 'this is a string' end;
->this is a string
so you can use it like this
select case when fild_01 ~ '\d{2}\/\d{2}\/\d{4}' then TO_DATE(fild_01,'DD/MM/YYYY')::text ELSE fild_01 end from test_table;
as you can see, case construction can't generalize two different types of data, so I had to convert them to the same type of text
Use the TRY_CONVERT function, with style 107
SELECT TRY_CONVERT(datetime, 'Jun 27 2021 12:22AM', 107)
Result
2021-06-27 00:22:00.000
This returns a null if the value is not a date
You can choose according to your needs.
When you want to set default value:
SELECT IIF(ISDATE(Val) = 1 , Val,'YOUR_DEFAULT_VALUE')
Whent default value not matter (It will be NULL):
SELECT TRY_CAST(NULL AS DATE)

Converting Varchar to Date and date Comparison

I am converting two Date columns to find the most recent one
SELECT ISNULL(CONVERT(varchar(10),REPLACE('10-07-2015','/','-'), 103),'01-01-1900'),
ISNULL(CONVERT(varchar(10),REPLACE('10/7/2015','/','-'), 103),'01-01-1900'),
CASE
WHEN ISNULL(CONVERT(varchar,REPLACE('10-07-2015','/','-'), 103),'01-01-1900') = ISNULL(CONVERT(varchar,REPLACE('10/7/2015','/','-'), 103),'01-01-1900')
THEN '10-07-2015'
END
My issue is some dates missing leading Zero in Day or Month and comparison is giving false results. Is there a better way to handle this? Other issue is one column has date with '/' and other have with '-'
Currently case is only checking on '=' but will add more to get the most recent
You can just convert those 2 varchars to the DATE type, then compare them.
You can find the date/datetime styles here
For those DD/MM/YYYY datestamps the 103 style would fit.
And to calculate the most recent between them, just wrap it in a CASE.
Example snippet:
declare #T table (
id int identity(1,1) primary key,
datestamp1 varchar(10),
datestamp2 varchar(10)
);
insert into #T (datestamp1, datestamp2) values
('5/9/2018','17/9/2018')
,('9-10-2018','16-10-2018')
,('15-10-2018','13-10-2018')
;
SELECT *,
TRY_CONVERT(DATE, datestamp1, 103) as date1,
TRY_CONVERT(DATE, datestamp2, 103) as date2,
CASE
WHEN TRY_CONVERT(DATE, datestamp1, 103) >= TRY_CONVERT(DATE, datestamp2, 103) THEN datestamp1
WHEN TRY_CONVERT(DATE, datestamp2, 103) IS NULL THEN datestamp1
ELSE datestamp2
END AS MostRecentDatestamp
FROM #T;
Returns:
id datestamp1 datestamp2 date1 date2 MostRecentDatestamp
1 5/9/2018 17/9/2018 2018-09-05 2018-09-17 17/9/2018
2 9-10-2018 16-10-2018 2018-10-09 2018-10-16 16-10-2018
3 15-10-2018 13-10-2018 2018-10-15 2018-10-13 15-10-2018

How to convert round number to data and time format

Two Column in table tblpress
Date Time
20160307 120949
20160307 133427
Need to be select below the format:
07-03-2016 12:09:49
07-03-2016 13:34 27
or
03-March-2016 12:09: 49 PM
03-March-2016 01:34: 27 PM
You can try below
select format(cast([Date] as date),'dd-MMMM-yyyy') as [Date],
TIMEFROMPARTS(LEFT([Time],2), SUBSTRING([Time],3,2), RIGHT([Time],2), 0,0) as [Time]
I think CAST/CONVERT will help you:
SELECT
CAST('20160307' AS date),
CAST(STUFF(STUFF('120949',3,0,':'),6,0,':') AS time)
And convert for out:
SELECT
CONVERT(varchar(20),NormalDate,105) OutDate, -- Italian style
CONVERT(varchar(20),NormalTime,108) OutTime -- hh:mi:ss
FROM
(
SELECT
CAST([Date] AS date) NormalDate,
CAST(STUFF(STUFF([Time],3,0,':'),6,0,':') AS time) NormalTime
FROM YourTable
) q
CAST and CONVERT (Transact-SQL)
And you can use FORMAT (Transact-SQL)
SELECT
FORMAT(GETDATE(),'dd-MM-yyyy'),
FORMAT(GETDATE(),'HH:mm:ss')
Best way to do it is to create a function :
create FUNCTION [dbo].[udfGetDateTimeFromInteger]
(
#intDate int,
#intTime int
)
RETURNS datetime
AS BEGIN
-- Declare the return variable here
DECLARE #DT_datetime datetime = NULL,
#str_date varchar(11),
#str_time varchar(8)
if(#intDate is not null and #intDate > 0)
begin
select #str_date = CAST( cast(#intDate as varchar(8)) AS date)
if #intTime=0
select #str_time ='000000'
else
select #str_time = right('0'+CONVERT(varchar(11),#intTime),6)
select #str_time =
SUBSTRING(#str_time,1,2)+':'+SUBSTRING(#str_time,3,2)+':'+SUBSTRING(#str_time,5,2)
select #DT_datetime = CAST(#str_date+' '+#str_time as datetime)
end
-- Return the result of the function
RETURN #DT_datetime
END
and then call it in select like :
declare #next_run_date int, #next_run_time int
select #next_run_date = 20160307
select #next_run_time = 130949
SELECT #next_run_date inputdate,
#next_run_time inputtime,
dbo.udfGetDateTimeFromInteger(#next_run_date, #next_run_time) outputdatetime
Output will be like :
inputdate inputtime outputdatetime
20160307 130949 2016-03-07 13:09:49.000
You said those are numbers, right? You can use datetimefromparts (or datetime2fromparts). ie:
select
datetimefromparts(
[date]/10000,
[date]%10000/100,
[date]%100,
[time]/10000,
[time]%10000/100,
[time]%100,0)
from tblpress;
DB Fiddle demo
Note that naming fields like that and also storing date and time like that is a bad idea.
I later noticed it was char fields:
select
cast([date] as datetime) +
cast(stuff(stuff([time],5,0,':'),3,0,':') as datetime)
from tblpress;

SQL Server - Converting date in "20140410" format to 04/10/2014 format

I have a table in a server that outputs the date in the following format YEARMONTHDAY
Example 20140410.
Question is how to I convert it to be as MONTH/DAY/YEAR, example 04/10/2014
Thanks!
David
Try this:
declare #theDate varchar(8)
set #theDate = '20140410'
select convert(varchar(10),cast(#theDate as date),101)
I think you can use:
SELECT convert(varchar, getdate(), 101);
Here is one way to do it:
declare #dt CHAR(8) = '20140131'
select #dt, CONVERT(DATE,#dt) as newDt
Here is a link on the CONVERT function http://msdn.microsoft.com/en-us/library/ms187928.aspx and one on date types http://msdn.microsoft.com/en-us/library/bb630352.aspx
Here are 2 different versions, one version for if all values are valid YYYYMMDD format, and one that will still work with invalid dates (but will return null for invalids).
DECLARE #tblTest TABLE (id int not null identity, myDate int not null)
INSERT INTO #tblTest(myDate)
VALUES(20140308),(20140410)
;
--QUERY 1: if all values in your table are valid dates, then you can use this
SELECT t.id, t.myDate
, myDateFormatted = CONVERT(varchar(10),CONVERT(DATE, CONVERT(VARCHAR(10),t.myDate)),101)
FROM #tblTest t
--NOW INSERT SOME INVALID DATES AS WELL
INSERT INTO #tblTest(myDate)
VALUES(20140132),(48)
;
--NOW IF THERE ARE INVALID DATE, THEN USING QUERY 1 WOULD CAUSE AN ERROR: Conversion failed when converting date and/or time from character string
--QUERY 2: if there are ANY invalid values in your table, then you can use this
SELECT t.id, t.myDate
, myDateFormatted =
CASE
WHEN ISDATE(t.mydate) = 1 and len(t.myDate) = 8
THEN CONVERT(varchar(10),CONVERT(DATE, CONVERT(VARCHAR(10),t.myDate)),101)
ELSE NULL --THIS IS AN INVALID DATE
END
FROM #tblTest t
;

How do I create a datetime from a custom format string?

I have datetime values stored in a field as strings. They are stored as strings because that's how they come across the wire and the raw values are used in other places.
For reporting, I want to convert the custom format string (yyyymmddhhmm) to a datetime field in a view. My reports will use the view and work with real datetime values. This will make queries involving date ranges much easier.
How do I perform this conversion? I created the view but can't find a way to convert the string to a datetime.
Thanks!
Update 1 -
Here's the SQL I have so far. When I try to execute, I get a conversion error "Conversion failed when converting datetime from character string."
How do I handle nulls and datetime strings that are missing the time portion (just yyyymmdd)?
SELECT
dbo.PV1_B.PV1_F44_C1 AS ArrivalDT,
cast(substring(dbo.PV1_B.PV1_F44_C1, 1, 8)+' '+substring(dbo.PV1_B.PV1_F44_C1, 9, 2)+':'+substring(dbo.PV1_B.PV1_F44_C1, 11, 2) as datetime) AS ArrDT,
dbo.MSH_A.MSH_F9_C2 AS MessageType,
dbo.PID_A.PID_F3_C1 AS PRC,
dbo.PID_A.PID_F5_C1 AS LastName,
dbo.PID_A.PID_F5_C2 AS FirstName,
dbo.PID_A.PID_F5_C3 AS MiddleInitial,
dbo.PV1_A.PV1_F2_C1 AS Score,
dbo.MSH_A.MessageID AS MessageId
FROM dbo.MSH_A
INNER JOIN dbo.PID_A ON dbo.MSH_A.MessageID = dbo.PID_A.MessageID
INNER JOIN dbo.PV1_A ON dbo.MSH_A.MessageID = dbo.PV1_A.MessageID
INNER JOIN dbo.PV1_B ON dbo.MSH_A.MessageID = dbo.PV1_B.MessageID
According to here, there's no out-of-the-box CONVERT to get from your yyyymmddhhmm format to datetime.
Your strategy will be parsing the string to one of the formats provided on the documentation, then convert it.
declare #S varchar(12)
set #S = '201107062114'
select cast(substring(#S, 1, 8)+' '+substring(#S, 9, 2)+':'+substring(#S, 11, 2) as datetime)
Result:
2011-07-06 21:14:00.000'
This first changes your date string to 20110706 21:14. Date format yyyymmdd as a string is safe to convert to datetime in SQL Server regardless of SET DATEFORMAT setting.
Edit:
declare #T table(S varchar(12))
insert into #T values('201107062114')
insert into #T values('20110706')
insert into #T values(null)
select
case len(S)
when 12 then cast(substring(S, 1, 8)+' '+substring(S, 9, 2)+':'+substring(S, 11, 2) as datetime)
when 8 then cast(S as datetime)
end
from #T
Result:
2011-07-06 21:14:00.000
2011-07-06 00:00:00.000
NULL
You can use CAST or CONVERT.
Example from the site:
G. Using CAST and CONVERT with
datetime data
The following example displays the
current date and time, uses CAST to
change the current date and time to a
character data type, and then uses
CONVERT display the date and time in
the ISO 8901 format.
SELECT
GETDATE() AS UnconvertedDateTime,
CAST(GETDATE() AS nvarchar(30)) AS UsingCast,
CONVERT(nvarchar(30), GETDATE(), 126) AS UsingConvertTo_ISO8601;
GO
Here is the result set.
UnconvertedDateTime UsingCast UsingConvertTo_ISO8601
----------------------- ------------------------------ ------------------------------
2006-04-18 09:58:04.570 Apr 18 2006 9:58AM 2006-04-18T09:58:04.570
(1 row(s) affected)
Generally, you can use this code:
SELECT convert(datetime,'20110706',112)
If you need to force SQL Server to use a custom format string, use the following code:
SET DATEFORMAT ymd
SELECT convert(datetime,'20110706')
A one liner:
declare #datestring varchar(255)
set #datestring = '201102281723'
select convert(datetime, stuff(stuff(#datestring,9,0,' '),12,0,':') , 112 )
Result:
2011-02-28 17:23:00.000
DECLARE #d VARCHAR(12);
SET #d = '201101011235';
SELECT CONVERT(SMALLDATETIME, STUFF(STUFF(#d,9,0,' '),12,0,':'));
Note that by storing date/time data using an inappropriate data type, you cannot prevent bad data from ending up in here. So it might be safer to do this:
WITH x(d) AS
(
SELECT d = '201101011235'
UNION SELECT '201101011267' -- not valid
UNION SELECT NULL -- NULL
UNION SELECT '20110101' -- yyyymmdd only
),
y(d, dt) AS
(
SELECT d,
dt = STUFF(STUFF(LEFT(d+'000000',12),9,0,' '),12,0,':')
FROM x
)
SELECT CONVERT(SMALLDATETIME, dt), ''
FROM y
WHERE ISDATE(dt) = 1 OR d IS NULL
UNION
SELECT NULL, d
FROM y
WHERE ISDATE(dt) = 0 AND d IS NOT NULL;
DECLARE #test varchar(100) = '201104050800'
DECLARE #dt smalldatetime
SELECT #dt = SUBSTRING(#test, 5, 2)
+ '/' + SUBSTRING(#test, 7, 2) + '/'
+ SUBSTRING(#test, 1, 4) + ' ' + SUBSTRING(#test, 9, 2)
+ ':' + SUBSTRING(#test, 11, 2)
SELECT #dt
Output:
2011-04-05 08:00:00