another Conversion failed when converting datetime from character string - sql

SELECT Asset.AssetID, AnsMaint.Answer, Convert(datetime, AnsMaint.Answer) as maintasdate
FROM Asset INNER JOIN
AssetAnswer AnsMaint ON AnsMaint.AssetID = Asset.AssetID INNER JOIN
AssetField FldMaint ON FldMaint.AssetFieldID = AnsMaint.AssetFieldID
WHERE FldMaint.FieldText = 'Maint. Agreement Term'
AND ISDATE(AnsMaint.Answer) = 1
AND Convert(datetime, AnsMaint.Answer) < DateAdd(d, 145, GetDate())
I get the error on the last part of the AND. If I comment the AND out, it works fine. My dates in the DB happen to be 10/10/2012 and are valid. IsDate should weed out anything that is not valid.
In DB the results (when I comment out the last line). I'm completely stumped.
106 10/10/2012 2012-10-10 00:00:00.000
115 10/10/2012 2012-10-10 00:00:00.000
MORE interesting tidbits. If I change the last AND line to
AND DateAdd(d, cast(Asset.MaintenanceFreq as int), Convert(datetime, AnsMaint.Answer)) < DateAdd(d, 45, GetDate())
it works. If I take out the 2nd parameter (the cast as int) and replace it with a number or a zero, it gives me the same error.
I'm stumped. Any help would be so much appreciated!
Oh, AssetMaint.Answer is a varchar field in the DB nothing I can do about that.

From the description, it sounds like the Answer column contains values for some records which can't be converted to a date, and SQL is choosing an execution plan which evaluates the CONVERT before the ISDATE.
Try using a CASE statement for the conversion instead:
WHERE FldMaint.FieldText = 'Maint. Agreement Term'
AND CASE ISDATE(AnsMaint.Answer)
WHEN 1 THEN Convert(datetime, AnsMaint.Answer, 103)
END < DateAdd(d, 145, GetDate())

It's a guess , but I'd say it was mm/dd/yyyy versus dd/mm/yyyy.
e.g. 10/10 is okay, but 20/10 or 10/20 might not be.
add the style parameter to the converts e.g.
Convert(datetime, AnsMaint.Answer,103)
You'll have to look up which one based on what ever date format is in your mis-typed field.

Related

Converting "42978.6736458333" varchar to datetime

I've a varchar column with a value of 42978.6736458333 that I want to convert back to a proper datetime. I've searched quite a bit and tried many of the suggestions but I cannot seem to find one that works with the data I have.
I got this value from excel when I did a CONCATENATE of all the fields in the sheet to do an insert to my DB; the output of the datetime column looks like "42978.6736458333" (the cell originally contained "2017-08-31 16:10:03"). I tried formatting and various things in excel to no avail.
Here are a few examples of what I've tried:
Select
convert(varchar(23), date, 112) DATE1,
convert(datetime, '20160805') DATE2,
convert(datetime, '2011-09-28 18:01:00', 120) DATE3,
dateadd(second, 42978.6736458333 * 24*24*60, '1899-12-31') DATE4
From
[dbo].[trainingLog]
Results:
DATE 1 = 42978.6736458333
DATE 2 = 2016-08-05 00:00:00.000
DATE 3 = 2011-09-28 18:01:00.000
DATE 4 = 1947-01-25 11:16:01.000
For every result. DATE 2/3/4 don't count up even though the original datetime varchar increments.
For example, here are more varchar values:
42981.5092361111
42982.7187615741
42983.8171527778
The above attempts return a value/date, but it's the same date even though my varchar value increments.
I expect any datetime format. I really only want the month/day/year in any format.
Try
SELECT CAST(42978.6736458333 AS DATETIME)
returns
2017-09-02 16:10:03.000
However SQL server uses 01/01/1900 as the epoch whereas your excel uses 30/12/1899 or 31/12/1899 as the epoch so it looks like you need to subtract 2 days off after you cast.
e.g.
SELECT dateadd(d, -2, CAST(42978.6736458333 AS DATETIME) )
returns
2017-08-31 16:10:03.000
From you comment I am not sure how you get your value as running
SELECT CAST(42981.5092361111 AS DATETIME)
returns for me
2017-09-05 12:13:18.000
This looks like an Excel time. So:
select dateadd(minute, 42978.6736458333 * 24*60, '1899-12-31')
If you try to use seconds, you will get an overflow error. If seconds are important, you can do:
select dateadd(day, floor(42978.6736458333), '1899-12-31') +
dateadd(second, (42978.6736458333 % 1)*24*60*60, 0)

Date conversion doesn't work in where clause

I am trying to query against the columns SOE (datetime field) and Answer (varchar field) from a table where NOT ALL Answer values are dates but some of them are. If I remove the datediff from the 'where' clause, I'm able to run the query just fine. But on including it, it errors out saying that 'Conversion failed when converting date and/or time from character string'.
For context, I'm using SQL Server 2014.
This is what my query looks like:
select ID,
convert(datetime, Answer, 121) as Answer,
datediff(dd,convert(datetime,
Answer, 121), SOE) as Days
from table
where Type in (1) and SOE between '2019-01-01' and '2019-03-31'
and FormLocation = 'M1005_INP_DISCHARGE_DT'
and PayorType = 'Medicare'
and Answer <> ' '
datediff(dd, convert(datetime, Answer, 121), SOE) <= 5
Any tips on how to resolve this would be appreciated.
Before doing the conversion to datetime make sure the data in the "Answer" field can be converted to date. Try this...
and ((isdate(Answer) = 1) and (datediff(dd, convert(datetime, Answer, 121), SOE) <= 5))
Since 2012 you can use try_convert().
...
datediff(dd, try_convert(datetime, Answer, 121), SOE) <= 5
...
try_convert() returns NULL if the conversion doesn't succeed. And so does datediff() then. So you might want to handle that case some way.
Using apply you can save yourself some repetitive code:
select ID,
answer_datetime as Answer,
datediff(day, answer_datetime, SOE) as Days
from table t cross apply
(values (try_convert(datetime, Answer, 121))) v(answer_datetime)
where Type in (1) and
SOE between '2019-01-01' and '2019-03-31' and
FormLocation = 'M1005_INP_DISCHARGE_DT' and
PayorType = 'Medicare' and
Answer <> ' ' and
datediff(day, answer_datetime, SOE) <= 5;
But you should really fix the data definitions so date/times are stored using the correct type.

Converting date and/or time from character string is failing

I have this query and I tried converting it to every format, I mean the date time etc but it doesn't work and throws error:
Conversion failed when converting date and/or time from character string.
SELECT W.Organization_ID,
W.NIT_No,
W.SchemeID,
OpeningDate,
OpeningTime,
GETDATE(),
WorkNo,
CONVERT(decimal(10, 2), W.Cost) AS Cost,
WorkName,
W.ExpiryDate as ExpiryDate,
CONVERT(VARCHAR,OpeningDate,106),
CASE WHEN
CONVERT(DATETIME, CONVERT(VARCHAR(20),OpeningDate,106) + ' '
+ CONVERT(VARCHAR(20),OpeningTime,108))< GETDATE()
THEN 1
ELSE 0 END AS OpeningVaild
FROM Works W
the CASE part throws error.
OpeningDate is of type Varchar and OpeningTime is of type Time.
Why?
You are converting just a TIME datatype not a DATETIME so you don't need to specify the style:
DECLARE #T TIME = '08:05:06';
SELECT CONVERT(VARCHAR(8), #T) AS [Time];
SELECT CAST(#T AS VARCHAR(8)) AS [Time];
Or since you are using CONVERT()pick the right style for TIME datatype which is 108 or 114, instead of 106
SELECT CONVERT(VARCHAR(8), #T, 108) AS [Time];
Update:
According to the error Msg, your problem is in the CASE part.
That because you are trying to concat a DATETIME with a VARCHAR datatype, look at here to what you'r converting:
CASE WHEN
CONVERT(DATETIME, CONVERT(VARCHAR(20),OpeningDate,106) + ' '
+ CONVERT(VARCHAR(20),OpeningTime,108))< GETDATE()
THEN 1
ELSE 0 END AS OpeningVaild
Also the column OpeningDate -according to the error Msg- is VARCHAR so your are convert a VARCHAR to VARCHAR then convert it again to DATETIME then you try to concatinate the DATETIME with the VARCHAR returned from converting OpeningTime column from TIMEto VARCHAR, then try to compare them with GETDATE() which is DATETIME datatype.
So you CASE should look like:
CASE WHEN
(
CAST(OpeningDate AS DATETIME) + -- VARCHAR to DATETIME
CAST(OpeningTime AS DATETIME) -- TIME to DATETIME
) < GETDATE()
THEN 1
ELSE 0 END AS OpeningVaild
A beside note, here in this line
CONVERT(VARCHAR,OpeningDate,106),
You are trying to convert a VARCHAR to VARCHAR and without specify the lenght too, so this line should be:
CONVERT(VARCHAR(10),CAST(OpeningDate AS DATE),106),
Finally, don't ever ever store DATE as VARCHAR, the DATE/ TIME/ DATEIME are there for a reason, so use them and all other datatypes wisely.
Here is a demo represent your issue, and how to fix it.
You can simplify this big time by changing the expression a little.
This way you don't have to convert and concatenate.
SELECT
CASE WHEN OpeningDate < GETDATE() - OpeningTime
THEN 1
ELSE 0 END AS OpeningVaild
Note I am assuming that Openingdate has the format dd-mon-yyyy. Otherwise you still need to convert it, but still shorter:
SELECT
CASE WHEN Convert(date, OpeningDate, 106) < GETDATE() - OpeningTime
THEN 1
ELSE 0 END AS OpeningVaild
So I understand the problem is with this part:
CASE WHEN CONVERT(DATETIME, CONVERT(VARCHAR(20),OpeningDate,106) + ' ' + CONVERT(VARCHAR(20),OpeningTime,108))< GETDATE() THEN 1 ELSE 0 END AS OpeningVaild
Update
Since I've first posted my answer it turns out that you store the opening date as varchar instead of date.
First, you should stop doing that. Never store dates in anything other than a Date column (unless you need them with time as well, and then use DateTime2).
For more information, read Aaron Bertrand's Bad habits to kick : choosing the wrong data type.
Assuming the data type of the column can't change, you wrote in the comments to the question:
#ZoharPeled: this is the format of openingdate 2017-04-10
Illustrating one of the problems caused by storing dates as strings - How can I, or anyone else for that matter, know if that's the 10th of April or the 4th of October? The answer is we can't.
So, assuming it's the 10th of April, you can convert it to DateTime using convert with 126 as the style parameter:
CASE
WHEN CONVERT(DateTime, OpeningDate, 126) + CAST(OpeningTime As DateTime) < GETDATE() THEN
1
ELSE
0
END As OpeningVaild
First version:
Assuming that the data type of OpeningDate is Date and the data type of OpeningTime is Time, Seems like you are attempting to figure out if these columns combination into a DateTime is before the current DateTime.
Instead of converting them into strings and back to DateTime, you can cast both to DateTime and simply add them together:
CASE
WHEN CAST(OpeningDate As DateTime) + CAST(OpeningTime As DateTime) < GETDATE() THEN
1
ELSE
0
END As OpeningVaild
Another option would be to use GETDATE() twice. I don't think it should matter in the select clause, but in the where clause it's important to use this option since the first one will make these columns non-seargable, meaning the database engine will not be able to use any indexes that might help the execution plan of the statement:
CASE
WHEN OpeningDate < CAST(GETDATE() AS DATE)
OR
(
OpeningDate = CAST(GETDATE() AS DATE)
AND OpeningTime <= CAST(GETDATE() AS TIME)
) THEN
1
ELSE
0
END AS OpeningVaild
That being said, your query also have CONVERT(VARCHAR,OpeningDate,106) - The 106 style returns a string representation of the date as dd mon yyyy - meaning 11 chars - so change that to CONVERT(CHAR(11),OpeningDate,106) Note that using varchar without specifying the length defaults to 30, which is not a problem in this case since it's more than he 11 chars you need, but it's a bad habit to not specify length and you should kick it.

converting varchar to datetime in tsql

I've studied all similar questions here, none of them works, what can be the problem? I want to convert varchar to date
convert(date,substring(replace(ent.Value,' ',''),1,10),103) < '20140101'
It returns error
Conversion failed when converting date and/or time from character string.
ent.Value here is something like '28/02/2014' Actually it works, when I enter something like
convert(date,substring('28/02/2013',1,10),103) < '20140101'
, but it doesn't work directly from the table
Thanks
To convert varchar to datetime : CONVERT(Datetime, '28/02/2014', 103) return the datetime like February, 28 2014 00:00:00+0000
To convert datetime to varchar : CONVERT(VARCHAR(10), datetime_field, 103) return something like '28/02/2014'
In both case you cannot compare it to this kind of text : '20140101'
You can change your text so both informations are ISO like : CONVERT(VARCHAR(10), CONVERT(Datetime, ent.Value, 103), 103) < '01/01/2014'
Or REPLACE(ent.Value,'/','') < '01012014'
But I don't think it's good to compare varchar => you can also do something like this : CONVERT(Datetime, '20140101', 112) :
CONVERT(Datetime, ent.Value, 103) < CONVERT(Datetime, '20140101', 112)
So your both field are in Datetime. ex : SQLFIDDLE DEMO
Break it down a bit: The first conversion works fine with the given example date string, but then you try and compare a DATE to a VARCHAR which requires an implicit conversion. That's never a good sign. However that actually works, so that aside the chances are that you have a date stored in text format that isn't a valid date. Since your examples use the UK date format, perhaps you have an American date in there (02/28/2013 - mm/dd/yyyy). If your default date format is UK style (i.e. you're not using American English settings) then it will fail as being out of range. You might also have entries which aren't dates at all with text in them like wibble or badly formatted dates like 02 Fub 2013.
Basically, you have a duff date somewhere in your table which you'll need to track down. Dates stored as text are a curse and to be avoided at all costs (although I appreciate that's not always possible when you inherit a legacy system - been there myself).
EDIT
To find your possible bad dates try this:
SELECT * FROM MyTable WHERE ISDATE(MyDateAsTextCol) <> 1

SQL Datetime Convert Error

I have have an SQL Statement which returns following error:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
SELECT * FROM eBV_Platz
WHERE (ADRID = 4436) AND (ID <> 5) AND (Status = 1)
AND (CONVERT(DATETIME, '01.03.2014', 102) >= PlaceFrom)
AND (CONVERT(DATETIME, '01.03.2014') <= PlaceTo)
OR (CONVERT(DATETIME, '31.03.2014') >= PlaceFrom)
AND (CONVERT(DATETIME, '31.03.2014') <= PlaceTo)
But this one works fine and the only difference are the date values:
SELECT * FROM eBV_Platz
WHERE (ADRID = 4436) AND (ID <> 5) AND (Status = 1)
and (CONVERT(DATETIME, '01.01.2000', 102) >= PlaceFrom)
AND (CONVERT(DATETIME, '01.01.2000') <= PlaceTo)
OR (CONVERT(DATETIME, '01.06.2001') >= PlaceFrom)
AND (CONVERT(DATETIME, '01.06.2001') <= PlaceTo)
I really don't understand this. Can anybody help me?
I'm betting that the second one does not work fine, rather it converts your dates to january 06 and january 01.
You need to give it a hint that you are using a day month year format.
Try instead:
(CONVERT(DATETIME, '31.03.2014', 103)
The 103 (from MSDN) interprets the date as dd/mm/yy
As #AlexK noted in the comments, these dont really need to be converted. You could simply use the strings as long as they were in a better format.
My assumption here is that you are using MSSQL. For a different platform, the syntax would be different.
As stated in the comments, use ISO 8601 date format to specify dates (yyyy-mm-ddThh:mm:ss[.mmm]).
This would change '31.03.2014' to '2014-03-31T00:00:00.000' and remove any ambiguity.