Compare 2 dates with diff datatypes - sql

I have a temp_table where I have to update status to Invalid date if Create_date is a future date.
Following is the update statement I am using :
Set dateformat dmy
UPDATE [Temp_table]
SET [Status]= 'InvalidCreateDate-Rejected'
WHERE CAST(Create_date AS DATETIME) >=getdate() and isdate(create_date)=1
But whenever I execute it I get error message as:
Msg 242, Level 16, State 3, Line 1 The conversion of a varchar data
type to a datetime data type resulted in an out-of-range value. The
statement has been terminated.
I tried converting Getdate and Create_date in diff formats and then compared still the same issue.
Sample Create_Dates:
05/15/1800
04/06/2011
23/04/2015
13/08/2016
02/21/2017
15/06/2017
Any solution on this?

your cast of create_date is coming across an invalid date and causing the error. the is_date function is a good idea, but it isn't going to prevent the cast from hitting an error earlier.
Set dateformat dmy
UPDATE [Temp_table]
SET [Status]= 'InvalidCreateDate-Rejected'
WHERE CAST(case when isdate(create_date)=1 then Create_date else null AS DATETIME) >=getdate()
You can use a date purposefully in the past instead of the null if the null causes issues, but casting a null to date and comparing it to a date should result in a false and have it removed from results

However, you could use case expression which could handle your different date formats
SELECT CONVERT(DATETIME, Create_Dates,
CASE
WHEN CAST(SUBSTRING(Create_Dates, 4, 2) AS INT) > 12
THEN 101
ELSE 103
END);
Result :-
1800-05-15 00:00:00.000
2011-06-04 00:00:00.000
2015-04-23 00:00:00.000
2016-08-13 00:00:00.000
2017-02-21 00:00:00.000
2017-06-15 00:00:00.000

Related

Removing millisecond from datetime throwing error

I have this code in SQL Server 2016
SELECT CONVERT (DATETIME, CONVERT(varchar(8), ExpiryDate))
I get this result:
ExpiryDate
------------------------
2020-08-03 00:00:00.000
How can I remove the .000 (the milliseconds part)?
Expected result should be:
2020-08-03 00:00:00
Please help
By not using a datetime, which is accurate to 1/300th of a second. Instead define your value as a datetime2(0), which is accurate to 1 second (due to having a precision of 0 on milliseconds):
SELECT CONVERT(datetime2(0),ExpiryDate)
FROM ...
You are confusing the internal format and the display format. If you want the value formatted in a particular way, then format it explicitly:
select CONVERT(VARCHAR(19), expirydate, 121)
You can add this into the table as a computed column:
alter table t add expirydate_display as (CONVERT(VARCHAR(19), expirydate, 121))

How do I stop SQL Server swapping the month and day?

I have the following query:
DECLARE #someDateTime DATETIME = '2019-12-01 00:00:00.000'; -- 1st December 2019
SELECT #someDateTime;
Result
2019-01-12 00:00:00.000
I expected the result to be 2019-12-01 00:00:00.000 (1st December 2019) - The month and the date swap for some unknown reason.
Until recently, I never had an issue with this format.
How do I enter the date in the format "YYYY-MM-DD HH:mm:ss.000", and have it maintain that format once assigned to a variable/displayed in a select?
What setting determines this format that may have changed?
Potentialy useful information
dbcc useroptions
Result:
Set Option | Value
---------- -----
...
language | British
dateformat | dmy
...
Things I tried:
Query 1
Chaning the date to something that would be invalid if swapped
DECLARE #someDateTime DATETIME = '2019-12-20 00:00:00.000';
SELECT #someDateTime;
Result:
Msg 242, Level 16, State 3, Line 4
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
Query 2
Setting the variable after it's been declared
DECLARE #someDateTime DATETIME;
SET #someDateTime = '2019-12-01 00:00:00.000';
SELECT #someDateTime;
Result - UNDESIRED:
2019-01-12 00:00:00.000
Query 3
Inserting the variable into a table variable
DECLARE #someDateTime DATETIME = '2019-12-01 00:00:00.000';
DECLARE #someTable TABLE (someDateTimeColumn DATETIME);
INSERT #someTable VALUES (#someDateTime);
SELECT * FROM #someTable
Result - UNDESIRED:
someDateTimeColumn
------------------
2019-01-12 00:00:00.000
Query 4
Inserting the data directly into a table variable
DECLARE #someTable TABLE (someDateTimeColumn DATETIME);
INSERT #someTable VALUES ('2019-12-01 00:00:00.000');
SELECT * FROM #someTable
Result: UNDESIRED
someDateTimeColumn
------------------
2019-01-12 00:00:00.000
Query 5
Changing the format of the entered string
DECLARE #someDateTime DATETIME = '01/12/2019';
SELECT #someDateTime;
Result - DESIRED
2019-12-01 00:00:00.000
Query 6
Changing the format of the entered string
DECLARE #someDateTime DATETIME = '2019-12-01T00:00:00.00';
SELECT #someDateTime;
Result - DESIRED:
2019-12-01 00:00:00.000
Query 7
Changing the format of the entered string
DECLARE #someDateTime DATETIME = '2019-12-01';
SELECT #someDateTime;
Result - UNDESIRED:
2019-01-12 00:00:00.000
Query 8
Using SET DATEFORMAT
SET DATEFORMAT ymd
DECLARE #someDateTime DATETIME = '2019-12-01';
SELECT #someDateTime;
Result - DESIRED
2019-12-01 00:00:00.000
You may use the literal format YYYYMMDD which is always intepreted as year-month-day, regardless of the locale settings of your SQL Server:
DECLARE #someDateTime DATETIME = '20191201 00:00:00.000';
One solution is to use the full ISO8601 format, ie 2019-12-01T00:00:00.000, another to use the unseparated date format, ie 20191201 00:00:00.000. A better solution though would be to switch to datetime2.
datetime2 was introduced 15 (or was it 11) years ago to get rid of datetime's quirks, like the millisecond inaccuracy, arbitrary precision, weird arithmetic and ... parsing idiosyncrasies. For example, datetime2's parsing of the ISO8601 format isn't affected by DATEFORMAT :
SET DATEFORMAT ydm
DECLARE #someDateTime DATETIME2(0) = '2019-12-01 00:00:00.000'
select #someDateTime
------
2019-12-01 00:00:00
This secures your code from unfortunate server setting modifications
After reading this article from #SMor's comment, a comment my colleague made from a google search, and remembering something I did a few months ago, I think I've worked out what's happening and what's changed.
My db user was, by default, set to:
language | us_english
dateformat | mdy
So when reading the string '2019-12-01' SQL Server was expecting mm-dd-yyyy.
SQL server is clever though. It sees the first part 2019 and realises that it's actually the year, so it shifts the year to the end, then tries again.*
It now has 12-01-2019 which matches the format it's expecting.
When you open your account properties in SSMS, the language drop down defaults to the first language in the list (Arabic).
I happend to be in there a few months ago for something unrelated and decided, to make sure I didn't accidently set it to Arabic, I'd change that as well.
I chose British.
My db user is now set to:
language | British
dateformat | dmy
So when reading the string '2019-12-01' SQL Server is expecting dd-mm-yyyy.
Once it's shifted the year, it becomes 12-01-2019 which it interprets as dd-mm-yyyy thus leaving me with January 12th 2019 instead of December 1st 2019
Today has been a long day.
*Please note this is a rather simplified explanation of how I understand this issue. This may not be how it actually functions in reality but works to satisfy my curiosity on this issue.

Getting error only when using select top 1000 query in sql

I have a view xyz_view which has around 16,000 records.
There are four date columns which have data in this format '2015-04-30 00:00:00.000'
When I use query
select *
from xyz_view
I get all the records without any problem but when I use
select top 1000 *
from xyz_view
I get an error:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value '2013-08-05 00:00:00.0' to data type int.
Even select top 100 * from xyz_view works. Anything over 300 is throwing above error.
Please help me understand on this.
I think something in data type of four columns are not datetime type. Because your value is: '2013-08-05 00:00:00.0'
If is datetime type, it is: '2013-08-05 00:00:00.000' (3 numbers for milliseconds)
In view, you can convert or cast columns to datetime type, like this:
CAST(columns AS DATETIME)
CONVERT(DATETIME, columns)
Your top < 1000 doesn't show an error because it doesn't fetch the row with erroneous data.
The error check is only running when you fetch the row where one of your column with data type int got a date value in it - 2013-08-05 00:00:00.0
Check this record by running a Select statement.
SELECT * FROM myTable
WHERE myColumn = '2013-08-05 00:00:00.0'
Base on the record you see, decide then if you would change the erroneous 2013-08-05 00:00:00.0 to any acceptable int value
UPDATE myTable
SET myColumn = 123
WHERE myColumn = '2013-08-05 00:00:00.0'

Why does CONVERT to datetime break for this query but not the other?

This query works fine:
select CONVERT(DATETIME, GroupAdminEffectiveDate, 101) from ExchangeSmallGroupEnrollment
group by GroupAdminEffectiveDate
and returns the following:
1900-01-01 00:00:00.000
2012-06-30 00:00:00.000
2012-07-01 00:00:00.000
2012-07-11 00:00:00.000
2012-07-23 00:00:00.000
2012-07-25 00:00:00.000
2012-08-01 00:00:00.000
2012-08-14 00:00:00.000
2012-08-26 00:00:00.000
2012-09-01 00:00:00.000
2012-09-03 00:00:00.000
However, the following query:
select CONVERT(DATETIME, GroupAdminEffectiveDate, 101) from ExchangeSmallGroupEnrollment
and I get the following the error:
Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.
Any ideas? Much appreciated.
UPDATE:
Query:
select distinct GroupAdminEffectiveDate from ExchangeSmallGroupEnrollment
Result:
(empty string)
06/30/2012
07/01/2012
07/11/2012
07/23/2012
07/25/2012
08/01/2012
08/14/2012
08/26/2012
09/01/2012
09/03/2012
I can't reproduce your error, so I suspect our definition of "empty string" differs or there is something else going on that you haven't revealed. In the meantime, since you are using SQL Server 2012, you can use TRY_PARSE for this, e.g. one of these expressions:
SELECT TRY_PARSE(GroupAdminEffectiveDate AS DATETIME USING N'en-us')
FROM dbo.ExchangeSmallGroupEnrollment;
SELECT TRY_PARSE(GroupAdminEffectiveDate AS DATETIME USING N'en-us')
FROM dbo.ExchangeSmallGroupEnrollment
GROUP BY GroupAdminEffectiveDate;
SELECT TRY_PARSE(GroupAdminEffectiveDate AS DATETIME USING N'en-us')
FROM dbo.ExchangeSmallGroupEnrollment
GROUP BY TRY_PARSE(GroupAdminEffectiveDate AS DATETIME USING N'en-us');
If you really want the 1900-01-01 to be a valid output, then:
SELECT COALESCE(TRY_PARSE(GroupAdminEffectiveDate AS DATETIME USING N'en-us'),
'19000101')
FROM dbo.ExchangeSmallGroupEnrollment
GROUP BY TRY_PARSE(GroupAdminEffectiveDate AS DATETIME USING N'en-us');
You first CAST your varchar column to Datetime and then CONVERT.
Declare #testvarchar VARCHAR(15) = '08/27/2012'
select CONVERT(datetime, Cast(#testvarchar as datetime), 101)
That should solve your conversion error
There might be that there are more 'non-date' fields in your database. One can be "" and another " ". When you group by or distinct, all end up being "" which implies NULL, and that is good to convert.
Otherwise it fails for " " (space).
check select length( GroupAdminEffectiveDate ) from ExchangeSmallGroupEnrollment
Maybe it will give you some clue?
check this:
select CONVERT(DATETIME, ISDATE( GroupAdminEffectiveDate), 101) from ExchangeSmallGroupEnrollment

IsDate Function in SQL evaluates invalid dates as valid

I am running a SQL Statement against imported data from Excel Files.
In this SQL I am checking if the users have entered dates properly by using IsDate function. Since this is a raw data that hasn't been converted yet, all dates are stored in a varchar data type field.
In some circumstances IsDate returns 1 (valid date) when there is clearly an incorrect date format entered by the user.
For Example:
07/001/2012
2012-07-002
007/002/2012
Any Suggestions on how to handle this problem?
SELECT *
FROM tblImport
WHERE (ISDATE(dt) = 0
AND (dt is not null AND dt <> ''))
Thanks!
p.s. Smacking users' did not help.
I do a lot of data conversion work and here is a function that I created and use it practically everyday to weed out the bad dates:
CREATE FUNCTION dbo.fnCheckDate
(#InDate nvarchar(50))
RETURNS DATETIME
AS
BEGIN
declare #Return DATETIME
select #return = CASE WHEN ISDATE(#InDate) = 1
THEN CASE WHEN CAST(#InDate as DATETIME) BETWEEN '1/1/1901 12:00:00 AM' AND '6/6/2079 12:00:00 AM'
THEN #InDate
ELSE null
END
ELSE null
END
return #return
END
GO
Results:
SELECT dbo.fnCheckDate('07/001/2012') --> Returns 2012-07-01 00:00:00.000
SELECT dbo.fnCheckDate('2012-07-002') --> Returns 2012-07-01 00:00:00.000
SELECT dbo.fnCheckDate('007/002/2012') --> Returns 2012-07-01 00:00:00.000
SELECT dbo.fnCheckDate('00/002/2012') --> Returns Null
SELECT dbo.fnCheckDate('006/031/2012') --> Returns Null
SELECT dbo.fnCheckDate('') --> Returns Null
Try setting the dateformat first - that worked for me when I was seeing exceptions.
set dateformat dmy
select IsDate(<column>)
from Table
maybe just check dt's LEN? however, it can not handle cases when the len is valid. maybe input validation should happen in the frontend?