Convert varchar to DateTime not working on table but works on individual values - sql-server

I have a table with column ImportDate of datatype varchar(100).
I want to convert its values from varchar to Datetime and for that I have used this query:
select
convert(datetime, ImportDate)
from ImportHistory
But it throws an exception with message
Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.
But when I individually select each value and run the statement it works fine. For example the below query works perfectly, and so do all the values in the table
select convert(Datetime, '1826-07-04 18:20:00')
There are no null values in that table and below are the values:
1826-07-04 18:20:00
1826-07-04 18:20:00
1917-11-08 11:11:00
2003-07-16 16:02:00
1984-06-08 00:00:00
2004-06-05 00:00:00
1826-07-04 18:20:00
1826-07-04 18:20:00
1917-11-08 11:11:00
2003-07-16 16:02:00
1984-06-08 00:00:00
2004-06-05 00:00:00

If you're using SQL Server 2012+, use TRY_PARSE or TRY_CONVERT in this kind of scenario:
DECLARE #ImportHistory TABLE (ImportDate VARCHAR(100))
INSERT #ImportHistory
VALUES
('1826-07-04 18:20:00'),
('1826-07-04 18:20:00'),
('1917-11-08 11:11:00'),
('2003-07-16 16:02:00'),
('1984-06-08 00:00:00'),
('2004-06-05 00:00:00'),
('1826-07-04 18:20:00'),
('1826-07-04 18:20:00'),
('1917-11-08 11:11:00'),
('Invalid!'),
('2003-07-16 16:02:00'),
('1984-06-08 00:00:00'),
('2004-06-05 00:00:00')
SELECT
ImportDate, TRY_CONVERT(datetime, ImportDate) as dt
FROM #ImportHistory
WHERE TRY_CONVERT(datetime, ImportDate) IS NULL
-- output: Invalid!, NULL
To find the invalid value. If you want invalid values to be converted to NULL, you can remove the WHERE clause and just use TRY_PARSE in place of CONVERT.
The dates you've listed are all valid, but it's very likely in your actual table you have at least one invalid date - or at least not one that can be parsed as is (extra space, month/day stored in different culture format, etc.).
If you must keep your column as a VARCHAR for some unknown reason and you want to make sure that applications don't insert unparsable dates into it, you could add a constraint
ALTER TABLE ImportHistory
ADD CONSTRAINT CK_ImportDate
CHECK(TRY_CONVERT(datetime, ImportDate) IS NOT NULL)
If you don't have SQL Server 2012+, you could try making a cursor to find the invalid data:
DECLARE #dt VARCHAR(100);
DECLARE #dt2 DATETIME;
BEGIN TRY
DECLARE test_cursor1 CURSOR FOR
SELECT Importdate FROM #ImportHistory
OPEN test_cursor1
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM test_cursor1 INTO #dt
SET #dt2 = CONVERT(datetime, #dt)
END
END TRY
BEGIN CATCH
SELECT #dt
END CATCH
-- output: Invalid!

This resolved the issue.
Select Convert(Datetime, LTRIM ( RTRIM ( REPLACE ( REPLACE ( REPLACE ( ImportDate, CHAR(10), ''), CHAR(13), ''), CHAR(9), '') ) )) from ImportHistory
Thank you All !!

Related

Confusing type conversion error (date-to-varchar throwing string-to-datetime error)

I have a table that tracks inserts, updates, and deletions to another table. This pattern has been used for years but has suddenly introduced an error when we added tracking of a DATE column.
This is not a string format issue. My input data is in ISO-8601 standard format.
I've cut out all but the necessary parts of the code to demonstrate the issue.
CREATE TABLE dbo.ChangeTrackingTable
(
oldValue VARCHAR(100) NULL,
newValue VARCHAR(100) NULL
);
GO
CREATE PROCEDURE dbo.usp_TestProcedure
(
#name VARCHAR(100),
#dateOfBirth DATE
)
AS
BEGIN
INSERT INTO dbo.ChangeTrackingTable
(
oldValue,
newValue
)
SELECT
List.oldFieldValue,
List.newFieldValue
FROM
(VALUES
(NULL, #name, IIF(#name IS NOT NULL, 1, 0)),
(NULL, #dateOfBirth, IIF(#dateOfBirth IS NOT NULL, 1, 0))
) AS List (oldFieldValue, newFieldValue, hasChanges)
WHERE
List.hasChanges = 1
END;
GO
The VALUES list is used to dynamically determine which columns are being touched.
When I execute the sproc with just the date, everything works fine.
DECLARE #date DATE = GETDATE();
EXEC dbo.usp_TestProcedure
#name = NULL,
#dateOfBirth = #date;
/*
oldValue newValue
NULL 2019-03-27
*/
But if I try to execute it with any value supplied for #name, whether or not a value for #date is supplied, I get the following error.
DECLARE #date DATE = GETDATE();
EXEC dbo.usp_TestProcedure
#name = 'Name',
#dateOfBirth = #date;
--Conversion failed when converting date and/or time from character string.
If I supply hard-coded values directly to the INSERT statement, it works fine. So I can know it's not happening at the table level on insert.
If I add an explicit cast to this line
(NULL, CAST(#dateOfBirth AS VARCHAR(100)), IIF(#dateOfBirth IS NOT NULL, 1, 0))
it works as well.
The problem occurs with DATETIMEOFFSET, DATETIME, and DATETIME2 types as well, so my use of DATE is not the issue.
My question is why am I getting a string > datetime conversion error when I'm trying to read a DATE value to be inserted into a VARCHAR column, but only in a VALUES list when there exists another non-date value in the result-set for List?
In refining the question itself to its basic structure, I discovered the underlying answer.
When using the pattern
SELECT *
FROM
(VALUES
(NULL, #name, IIF(#name IS NOT NULL, 1, 0)),
(NULL, #dateOfBirth, IIF(#dateOfBirth IS NOT NULL, 1, 0))
) AS List (oldFieldValue, newFieldValue, hasChanges)
SQL Server will need to create a table in memory, and each of those columns needs an assigned datatype. This datatype is not assigned arbitrarily, but methodically according to a well-documented order of Data Type Precedence.
All the date-types appear very high in this list, so my use of DATE takes precedence over any CHAR or VARCHAR type that also appears in the table.
The column in my List table is assigned the highest-precedence type: DATE.
The error is being thrown when the VARCHAR value, 'Name' is being implicitly cast to the data-type of the column, which is DATE. Not when the #date parameter is inserted into the VARCHAR column of the table.

How to fix (Arithmetic overflow error converting expression to data type datetime) error in SQL Server

I have created a procedure for the purpose of fetching the yesterday data from an Oracle database table and insert it into a SQL Server 2012 table.
Using the following
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp
SELECT
LEAD(CONVERT(VARCHAR, CONVERT(DATETIME, '01-JAN-1970 03:00:00', 120) + [DAT_CLOSEDATE] / (24 * 60 * 60), 120), 1, CONVERT(VARCHAR, CONVERT(DATETIME, '01-JAN-1970 03:00:00', 120) + [DAT_CLOSEDATE] / (24 * 60 * 60), 120)) OVER (PARTITION BY [TXT_TICKETNUMBER] ORDER BY [DAT_CLOSEDATE]) AS [CLOSE_DATE]
INTO #Temp
FROM OPENQUERY(ORACLE_DB, 'SELECT DAT_CLOSEDATE ,TXT_TICKETNUMBER
FROM SCHEME.TABLE')
WHERE
[DAT_CLOSEDATE] = DATEADD(d, -1, GETDATE())
SELECT * FROM #Temp
Everything is working as expected when I don't use the WHERE condition.
But once I use the WHERE condition, the following error appears
Msg 8115, Level 16, State 2, Line 4
Arithmetic overflow error converting expression to data type datetime.
NOTE:
The DAT_CLOSEDATE column datatype in the Oracle table is float and its datetime in sql server .
I used the LEAD and CONVERT functions in order to convert its values to be a datetime datatype
I have tried to convert it to date datatype as following.
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp
SELECT
lead(convert(varchar,convert(date,'01-JAN-1970 03:00:00',120) +
[DAT_CLOSEDATE]/(24*60*60), 120),1,convert(varchar,convert(date,'01-JAN-
1970 03:00:00',120) + [DAT_CLOSEDATE]/(24*60*60), 120)) over(partition by
[TXT_TICKETNUMBER] order by [DAT_CLOSEDATE])AS [CLOSE_DATE]
INTO #Temp
FROM OPENQUERY(ORACLE_DB, 'SELECT DAT_CLOSEDATE ,TXT_TICKETNUMBER
FROM SCHEME.TABLE')
WHERE [DAT_CLOSEDATE] = DATEADD(d,-1,GETDATE())
SELECT * FROM #Temp
But I got this error
Msg 206, Level 16, State 2, Line 4
Operand type clash: date is incompatible with float
sample data for DAT_CLOSEDTE column in the oracle table which is FLOAT
DAT_CLOSEDATE
1531038410
1531038433
1531038438
1531038447
1531038449
1531038450
1531038506
1531038506
One of the resolution am looking for is I expect OPENQUERY syntax to be something like the following:
OPENQUERY(ORACLE_DB, 'SELECT DAT_CLOSEDATE, TXT_TICKETNUMBER
FROM SCHEME.TABLE
WHERE [DAT_CLOSEDATE] = trunc(sysdate)-1')
but it needs to be converted from FLOAT to DATE data type first.
Here's an example snippet that uses an extra sub-query to transform the FLOAT to a DATETIME.
Which makes further calculations easier.
Since it's an example, the insert into a temp table isn't used.
declare #Table table (TXT_TICKETNUMBER VARCHAR(30), DAT_CLOSEDATE FLOAT);
insert into #Table (TXT_TICKETNUMBER, DAT_CLOSEDATE) values
('foo000042', ((CONVERT(float, DATEADD(hour,-24,GETDATE()))*86400.0)-(25567.0*86400))),
('foo000042', ((CONVERT(float, DATEADD(hour,-23,GETDATE()))*86400.0)-(25567.0*86400))),
('bar000042', ((CONVERT(float, DATEADD(hour,-22,GETDATE()))*86400.0)-(25567.0*86400))),
('bar000042', ((CONVERT(float, DATEADD(hour,-21,GETDATE()))*86400.0)-(25567.0*86400)));
SELECT
TICKETNUMBER,
CLOSEDATETIME,
DAT_CLOSEDATE,
LEAD(CloseDatetime) OVER (PARTITION BY TICKETNUMBER ORDER BY CLOSEDATETIME) AS NextCLOSEDATETIME
FROM
(
select
TXT_TICKETNUMBER AS TICKETNUMBER,
DATEADD(hour,3,CONVERT(datetime,25567.0+(DAT_CLOSEDATE/86400.0))) AS CLOSEDATETIME,
DAT_CLOSEDATE
from
(
-- put the openquery here instead
select TXT_TICKETNUMBER, DAT_CLOSEDATE
from #Table
) q1
) q2
WHERE CAST(CLOSEDATETIME AS DATE) = CAST(DATEADD(day,-1,GETDATE()) AS DATE)
But if you would change that Oracle query to transform that "DAT_CLOSEDATE" to a string.
For example in the YYYY-MM-DD HH24:MI:SS format.
Then that would probably makes the conversion to a T-SQL DATETIME a tad easier.

How to change datetime format of varchar datatype column

How to change datetime format of varchar datatype column in SQL Server.
Datatype of column [Value] is varchar. I cannot change datatype into datetime because this column contains numeric values also. This table is being updated by query. I need the format yyyy-mm-dd hh:mm:ss(24h). How?
You can use Try_Convert() in concert with IsNull()
To be clear. The result is still a string
Example
Declare #YourTable table (Value varchar(50))
Insert Into #YourTable values
('268142')
,('Jan 1 1900 12:04PM')
Select *
,NewVal = IsNull(format(try_convert(datetime,Value),'yyyy-MM-dd HH:mm:ss'),Value)
From #YourTable
Returns
Value NewVal
268142 268142
Jan 1 1900 12:04PM 1900-01-01 12:04:00
EDIT
Format() is not known to be a performer, and should be used sparingly. Another approach may be
NewVal = IsNull(try_convert(varchar(50),try_convert(datetime,Value),120),Value)
You can use this case-convert statement:
declare #date varchar(max)
set #date='Jan 1 1999 12:00AM'
Select case when right(#date,2)='AM' then convert(datetime,SUBSTRING(#date,1,len(#date)-2)+':00',121)
else dateadd(hour,12,convert(datetime,SUBSTRING(#date,1,len(#date)-2)+':00',121)) end

Convert VARCHAR in format YYMMDD to YYYYMMDD and ignore invalid date formats

I have a table with a VARCHAR field called ArrivalDate in format yymmdd (such as 170202).
I am writing a query which converts it to yyyymmdd so it should become 20170202.
However my problem is that I need to cater for the case when inappropriate data is entered into the field, and my query needs to exclude that data. I am achieving this exclusion by using the ISDATE function of TSQL. I also need to select the least recent entry (I'm using order by asc for this).
I am using a variety of converts to write this query, below is my implementation with a sample table and data.
Declare #tmp TABLE (theDates VARCHAR(MAX))
INSERT INTO #tmp VALUES('170202')
SELECT TOP 1 t.theDates
WHEN (ISDATE(t.theDates) = 1) THEN CONVERT( VARCHAR(max),CONVERT(datetime t.theDates), 112)
FROM #tmp t
WHERE (ISDATE(t.theDates) = 1)
ORDER BY CAST(t.theDates as DATE)
However I do not like my approach and it occasionally fails conversion and throws an error with values such as 02/02/02 which breaks the query. Can someone please show me a better way of writing this functionality.
Much appreciated!
You can use TRY_CONVERT and CONVERT to get the correct format and convert the value. Then check that the string is exactly 6 character to prevent other formats from being returned.
SELECT
convert(char(10),convert(date, theDates, 12),112)
FROM
(values('02/02/02'),('170202')) x(theDates)
WHERE
try_convert(date, theDates, 12) is not null
and len(theDates) = 6
You can use cast(#date as datetime)
declare #date varchar(max);
set #date='170202';
select
CASE WHEN (ISDATE(cast(#date as datetime)) = 1)
THEN CONVERT(VARCHAR(max), CONVERT(datetime, cast(#date as datetime)), 112) end
from table
set #date='02/02/02';
select
CASE WHEN (ISDATE(cast(#date as datetime)) = 1)
THEN CONVERT(VARCHAR(max), CONVERT(datetime, cast(#date as datetime)), 112) end
from table
please use create function for check dateformat is Valid or not and use this fun in your query inside cash clouse.
ALTER FUNCTION dbo.f_CheckDate
(#InDate nvarchar(25))
RETURNS DATE
AS
BEGIN
declare #Return DATETIME
select #return = CASE WHEN ISDATE(#InDate) = 1
THEN #InDate
ELSE NULL
END
return #return
END
You could use TRY_CAST or TRY_CONVERT if value cannot be cast it will return NULL.
SELECT
TRY_CAST('20170228' AS DATETIME),
TRY_CAST('170228' AS DATETIME),
TRY_CONVERT(DATETIME, '20170228'),
TRY_CONVERT(DATETIME, '170228')
This works for SQL Server 2012 and newer.

Conversion failed when converting date and/or time from character string in SQL SERVER 2008

I have below SQL.
UPDATE student_queues
SET Deleted=0,
last_accessed_by='raja',
last_accessed_on=CONVERT(VARCHAR(24),'23-07-2014 09:37:00',113)
WHERE std_id IN ('2144-384-11564')
AND reject_details='REJECT'
when I ran the above SQL the below exception has been throwed.
Conversion failed when converting date and/or time from character string.
If you're trying to insert in to last_accessed_on, which is a DateTime2, then your issue is with the fact that you are converting it to a varchar in a format that SQL doesn't understand.
If you modify your code to this, it should work, note the format of your date has been changed to: YYYY-MM-DD hh:mm:ss:
UPDATE student_queues
SET Deleted=0,
last_accessed_by='raja',
last_accessed_on=CONVERT(datetime2,'2014-07-23 09:37:00')
WHERE std_id IN ('2144-384-11564') AND reject_details='REJECT'
Or if you want to use CAST, replace with:
CAST('2014-07-23 09:37:00.000' AS datetime2)
This is using the SQL ISO Date Format.
Seems like last_accessed_on, is a date time, and you are converting '23-07-2014 09:37:00' to a varchar. This would not work, and give you conversion errors. Try
last_accessed_on= convert(datetime,'23-07-2014 09:37:00', 103)
I think you can avoid the cast though, and update with '23-07-2014 09:37:00'. It should work given that the format is correct.
Your query is not going to work because in last_accessed_on (which is DateTime2 type), you are trying to pass a Varchar value.
You query would be
UPDATE student_queues SET Deleted=0 , last_accessed_by='raja', last_accessed_on=convert(datetime,'23-07-2014 09:37:00', 103)
WHERE std_id IN ('2144-384-11564') AND reject_details='REJECT'
DECLARE #FromDate DATETIME
SET #FromDate = 'Jan 10 2016 12:00AM'
DECLARE #ToDate DATETIME
SET #ToDate = 'Jan 10 2017 12:00AM'
DECLARE #Dynamic_Qry nvarchar(Max) =''
SET #Dynamic_Qry='SELECT
(CONVERT(DATETIME,(SELECT
CASE WHEN ( ''IssueDate'' =''IssueDate'') THEN
EMP_DOCUMENT.ISSUE_DATE
WHEN (''IssueDate'' =''ExpiryDate'' ) THEN
EMP_DOCUMENT.EXPIRY_DATE ELSE EMP_DOCUMENT.APPROVED_ON END
CHEKDATE ), 101)
)FROM CR.EMP_DOCUMENT as EMP_DOCUMENT WHERE 1=1
AND (
CONVERT(DATETIME,(SELECT
CASE WHEN ( ''IssueDate'' =''IssueDate'') THEN
EMP_DOCUMENT.ISSUE_DATE
WHEN (''IssueDate'' =''ExpiryDate'' ) THEN EMP_DOCUMENT.EXPIRY_DATE
ELSE EMP_DOCUMENT.APPROVED_ON END
CHEKDATE ), 101)
) BETWEEN '''+ CONVERT(CHAR(10), #FromDate, 126) +''' AND '''+CONVERT(CHAR(10), #ToDate , 126
)
+'''
'
print #Dynamic_Qry
EXEC(#Dynamic_Qry)

Resources