Converting m/d/y strings to datetime yields conversion error - sql

Here is the code I'm using:
SELECT SalesItemPK
,FieldName
,Value /*Convert date to the first of the selected month*/
FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN(
1425
,1225
,1556
,1589
,1599
,1588
,1590)
AND FieldName = 'Estimated Ship Date'
AND CONVERT(DATETIME, Value) >= CONVERT(DATETIME, '1/1/2010')
(I'm selecting just those PKs because those are all the rows in the query.)
This is the error I receive:
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value
Below is a sample of the data returned from my view. The final solution actually converts the values to the first of their respective months. But an error is thrown either way.
When I remove the WHERE, it works fine. So there's something strange going on there I can't seem to figure out so far. Any ideas?

Odds are, either the date is being interpreted as d/m/y (and the first row fails because there is no 18th month), or you have a piece of data in there where the first part (month) is > 12.
To find offending rows:
SELECT Value FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN (1425,1225,1556,1589,1599,1588,1590)
AND ISDATE(Value) = 0;
(And if you find offending rows, obviously, fix them.)
You can also make sure the values are interpreted as m/d/y (and won't fail on other garbage in the column) using:
SELECT SalesItemPK, FieldName, Value,
FirstOfMonth = CASE WHEN ISDATE(Value) = 1 THEN
DATEADD(DAY,1-DAY(CONVERT(DATETIME,Value,101)),CONVERT(DATETIME,Value,101)) END
FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN (1425,1225,1556,1589,1599,1588,1590)
AND FieldName = 'Estimated Ship Date'
AND CASE WHEN ISDATE(Value) = 1 THEN CONVERT(DATETIME, Value, 101)
ELSE NULL END >= '20100101';
Also note that just because you perform a WHERE clause on the PK values, does not mean SQL Server has to evaluate that condition first. It could try to convert every row in the view (heck, every row in the source table) to a DATETIME first. Which is why I also added a CASE expression to the SELECT list, just in case. No pun intended. I also offered my suggestion on how to calculate the first of the month easily (a lot of people tend to do really strange things, like convert to string).
Do you have any idea how much simpler this query would be if the view exposed a separate column as datetime, e.g.
, DateValue = CASE WHEN ISDATE(Value) = 1 THEN CONVERT(DATETIME, Value, 101)
Then the query could be:
SELECT SalesItemPK, FieldName, DateValue,
FirstOfMonth = DATEADD(DAY, 1-DAY(DateValue), DateValue)
FROM [Oasis].[dbo].[vw_SALES_SalesItemDetails]
WHERE SalesItemPK IN (1425,1225,1556,1589,1599,1588,1590)
AND DateValue >= '20100101';
In fact the view could also expose the FirstOfMonth calculation for you too.
These are some of the many, many, many reasons why you should never, ever, ever store date/time data as strings. At the very least, change the view to present these strings as a completely language-, dateformat- and region-neutral string (yyyymmdd) instead of mm/dd/yyyy.

Its probably one of your date values is not in correct format. Try the following query to find list of values that cant be converted as date.
select value from [Oasis].[dbo].[vw_SALES_SalesItemDetails] where isdate(value) = 0

Related

Convert from nvarchar to datetime from a large record table with potentially bad date strings

I have a main table called Cases that I am inserting data into. I have a alternative table where all of the raw data called rawTableData is stored and then sent to the main table.
I have a nvarchar column in my rawTableDatathat stores a datetime string in this format
2016-04-04-10.50.02.351232
I have a column in my Cases table that has a datatype of DATETIME.
I first tried to find the bad data in this method below
SELECT CONVERT(datetime, nvarcharDateColumn, 103)
FROM rawTableData
WHERE ISDATE(CONVERT(datetime, nvarcharDateColumn, 103)) != 1
And I get the error below
The conversion of nvarchar data type to a datetime data type resulted in an out-of-range value.
Then I tried a different approach hoping to find all of the out of range values
SELECT nvarcharDateColumn
FROM rawTableData
WHERE ISDATE(nvarcharDateColumn)
But that only returns all rows since its nvarchar.
Again, I kept going and tried a different approach
SELECT CONVERT(DATETIME, CASE WHEN ISDATE(nvarcharDateColumn) = 1 THEN nvarcharDateColumn END, 103)
FROM rawTableData
I am not sure what I am doing wrong here and any help would be appreciated.
I am using SQL Server 2012
You can use TRY_CONVERT:
SELECT nvarchardatecolumn, TRY_CONVERT(date, nvarchardatecolumn)
FROM rawTableData
And if you only want to return the invalid dates, use a derived table:
SELECT *
FROM (SELECT nvarchardatecolumn, TRY_CONVERT(date, nvarchardatecolumn) DateCheck
FROM rawTableData
) A
WHERE DateCheck IS NULL

trouble with string to date conversion

Greetings StackWarriors....
I am in need of some help.
I have this SQL Select statement:
SELECT GEOID, cast(LEFT(PP.PurchaseDate,4) + RIGHT(Left(PP.PurchaseDate,6),2) as integer) AS Month
FROM PropertyParametersNew PP
join PropertyTracts PT on PP.ParcelID = PT.PARCELID
WHERE
PP.PurchaseDate >0
and convert(datetime, PP.PurchaseDate, 112)>= DATEADD(MONTH,-1,getdate())
The intent in this query is trying to get GEOID, and the year/month associated in the PurchaseDate Column.
and I'm getting this error:
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.
I realized that inside that column, I have yyyymmdd formatted dates that have 00's in the mm and dd. Examples include 20130000 and 20120300.
I am trying to rephrase the sql query to handle those entries.
My owners say that 0000 should reflect January 1, and 00 should reflect the 1st of the month.
How can I restructure this SQL statement to reflect this value, so I can get Year/Month combo without the conversion failure?
Thanks.
You can use REPLACE to fix values in PurchaseDate, then simply use fixed field in its place:
(edit made after correct remark by #t-clausen)
SELECT GEOID,
cast(LEFT(x.PurchaseDate,4) + RIGHT(Left(x.PurchaseDate,6),2) as integer) AS Month
FROM PropertyParametersNew PP
CROSS APPLY (SELECT CASE WHEN RIGHT(PP.PurchaseDate, 4) = '0000'
THEN LEFT(PP.PurchaseDate, 4) + '0101'
WHEN RIGHT(PP.PurchaseDate, 2) = '00'
THEN LEFT(PP.PurchaseDate, 6) + '01'
ELSE PurchaseDate
END) x(PurchaseDate)
JOIN PropertyTracts PT on PP.ParcelID = PT.PARCELID
WHERE
PP.PurchaseDate >0
and convert(datetime, x.PurchaseDate, 112)>= DATEADD(MONTH,-1,getdate())
If, for example, PP.PurchaseDate is equal to 20130000, then the above query sets x.PurchaseDate equal to 20130101 and uses this value inside CONVERT as well as in SELECT clause.
For all this to work PP.PurchaseDate must be of fixed length (8 characters).
Best senario would be fixing the data to date second best would be changing your dates to be valid dates as char(8).
But your question is how to write your select.
You should not convert the purchase date to datetime, you should go the other way and convert the getdate() to char(8). This will give you a better performance. Then there is the issue of the varchar being 20130000. You can compensate by subtracting 1 from the date and ask for a greater value instead of greater equal.
The answer is quite simple and improves performance because you don't have a conversion on your column:
WHERE
PP.PurchaseDate >0
and PP.PurchaseDate >
CONVERT(char(8),DATEADD(MONTH,-1,getdate())-1, 112)

finding data lying between a specific date range in sql

I want to find records from my database which lie between any user input date range(say between 10/2/2008 to 26/9/2024). I tried using
SELECT NAME
,TYPE
,COMP_NAME
,BATCH_NO
,SHELF
,MFG_DATE
,EXP_DATE
,QTY
,VAT
,MRP
FROM STOCK_LOCAL
WHERE
convert(VARCHAR(20), EXP_DATE, 103)
BETWEEN convert(VARCHAR(20), #MEDICINEEXP_DATE, 103)
AND convert(VARCHAR(20), #MEDICINEEXPDATE, 103)
but with this query i need to enter perfect date range which is available in my database, it is not giving me data lying in between any date entered.
Thanks in advance
Since it is a poolr designed schema there isnt going to be any decent/Efficient solution for this.
In sql server if you are storing Date or Date & Time data. Use the Data or DATETIME datatypes for your columns.
In your case you are trying to compare a string with passed date. and even when you tried to convert the string (Date) into date datatype you didnt do it correctly.
My suggestion would be Add new columns to your table with Date datatype and update these columns with existing date/string values.
For now you can convert the Date(string) into date datatype using the following code.
DECLARE #MEDICINEEXP_DATE DATE = 'SomeValue1'
DECLARE #MEDICINEEXPDATE DATE = 'SomeValue1'
SELECT query....
FROM TableName
WHERE
CAST(
RIGHT(EXP_DATE, 4)
+SUBSTRING(EXP_DATE,CHARINDEX('/',EXP_DATE)+1,2)
+LEFT(EXP_DATE,2)
AS DATE) >= #MEDICINEEXP_DATE
AND CAST(
RIGHT(EXP_DATE, 4)
+SUBSTRING(EXP_DATE,CHARINDEX('/',EXP_DATE)+1,2)
+LEFT(EXP_DATE,2)
AS DATE) <= #MEDICINEEXPDATE
Note
This solution will get you the expected results but very inefficient method. It will not make use of any indexses on your EXP_DATE Column even if you have a very buffed up index on that column.

Insert converted varchar into datetime sql

I need to insert a varchar in my table. The type in the table is a datetime so I need to convert it. I didn't think this would be to big of a problem however it keeps inserting 1900-01-01 00:00:00.000 instead of the date I want. When I do a select with my converted date it does show me the correct date.
I'll show you the code:
INSERT INTO Item (CategoryId, [Date], Content, CreatedOn)
SELECT
CategoryId, Convert(datetime, '28/11/2012', 103), Content, GetDate()
FROM
Item i
JOIN
Category c ON i.CategoryId = c.Id
JOIN
Division d ON d.Id = c.DivisionId
WHERE
Date = Convert(datetime, '31/03/2005', 103)
AND d.Id = '142aaddf-5b63-4d53-a331-8eba9b0556c4'
The where clause works perfectly and gives me the filtered items I need, all data is correctly inserted except for the converted date. The gives like I said 1900-...
If I just do the select so:
SELECT CategoryId, Convert(datetime, '28/11/2012', 103), Content, GetDate()
FROM Item i
JOIN Category c ON i.CategoryId = c.Id
JOIN Division d ON d.Id = c.DivisionId
WHERE Date = Convert(datetime, '31/03/2005', 103) AND d.Id = '142aaddf-5b63-4d53-a331-8eba9b0556c4'
I get the correct date being: 2012-11-28 00:00:00.000. I have tried to use a different conversion like:
Convert(datetime, '20121128')
But that just gives the same problem. Anyone that sees what I'm doing wrong?
Thx
If you must use a string-based date format, you should pick one that is safe and works in every SQL Server instance, regardless of date format, language and regional settings.
That format is known as ISO-8601 format and it's either
YYYYMMDD (note: **NO** dashes!)
or
YYYY-MM-DDTHH:MM:SSS
for a DATETIME column.
So instead of
Convert(datetime, '28/11/2012', 103)
you should use
CAST('20121128' AS DATETIME)
and then you should be fine.
If you're on SQL Server 2008 - you could also look into using DATE (instead of DATETIME) for cases when you only need the date (no time portion). That would be even easier than using DATETIME and having the time portion always be 00:00:00
Just wanted to throw out the fact that I found this SO Question (and many others like it) years later while trying to find the answer to my problem.
If you are troubleshooting this inside a stored procedure, the parameter of the stored procedure is where you need to modify. The programmer who created the code I'm troubleshooting had #ddt CHAR(10) and no modifications inside the stored procedure resolved the problem. I had to change the parameter to #ddt smalldatetime.

Compare DATETIME and DATE ignoring time portion

I have two tables where column [date] is type of DATETIME2(0).
I have to compare two records only by theirs Date parts (day+month+year), discarding Time parts (hours+minutes+seconds).
How can I do that?
Use the CAST to the new DATE data type in SQL Server 2008 to compare just the date portion:
IF CAST(DateField1 AS DATE) = CAST(DateField2 AS DATE)
A small drawback in Marc's answer is that both datefields have been typecast, meaning you'll be unable to leverage any indexes.
So, if there is a need to write a query that can benefit from an index on a date field, then the following (rather convoluted) approach is necessary.
The indexed datefield (call it DF1) must be untouched by any kind of function.
So you have to compare DF1 to the full range of datetime values for the day of DF2.
That is from the date-part of DF2, to the date-part of the day after DF2.
I.e. (DF1 >= CAST(DF2 AS DATE)) AND (DF1 < DATEADD(dd, 1, CAST(DF2 AS DATE)))
NOTE: It is very important that the comparison is >= (equality allowed) to the date of DF2, and (strictly) < the day after DF2. Also the BETWEEN operator doesn't work because it permits equality on both sides.
PS: Another means of extracting the date only (in older versions of SQL Server) is to use a trick of how the date is represented internally.
Cast the date as a float.
Truncate the fractional part
Cast the value back to a datetime
I.e. CAST(FLOOR(CAST(DF2 AS FLOAT)) AS DATETIME)
Though I upvoted the answer marked as correct. I wanted to touch on a few things for anyone stumbling upon this.
In general, if you're filtering specifically on Date values alone. Microsoft recommends using the language neutral format of ymd or y-m-d.
Note that the form '2007-02-12' is considered language-neutral only
for the data types DATE, DATETIME2, and DATETIMEOFFSET.
To do a date comparison using the aforementioned approach is simple. Consider the following, contrived example.
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
CONVERT(char(8), OrderDate, 112) = #filterDate
In a perfect world, performing any manipulation to the filtered column should be avoided because this can prevent SQL Server from using indexes efficiently. That said, if the data you're storing is only ever concerned with the date and not time, consider storing as DATETIME with midnight as the time. Because:
When SQL Server converts the literal to the filtered column’s type, it
assumes midnight when a time part isn’t indicated. If you want such a
filter to return all rows from the specified date, you need to ensure
that you store all values with midnight as the time.
Thus, assuming you are only concerned with date, and store your data as such. The above query can be simplified to:
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
OrderDate = #filterDate
You can try this one
CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000')
I test that for MS SQL 2014 by following code
select case when CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000') then 'ok'
else '' end
You may use DateDiff and compare by day.
DateDiff(dd,#date1,#date2) > 0
It means #date2 > #date1
For example :
select DateDiff(dd, '01/01/2021 10:20:00', '02/01/2021 10:20:00')
has the result : 1
For Compare two date like MM/DD/YYYY to MM/DD/YYYY .
Remember First thing column type of Field must be dateTime.
Example : columnName : payment_date dataType : DateTime .
after that you can easily compare it.
Query is :
select * from demo_date where date >= '3/1/2015' and date <= '3/31/2015'.
It very simple ......
It tested it.....