Using Parameters in DATEADD function of a Query - sql-server

I am trying to us the DateAdd function of SQL in my Query. The problem is when I use a parameter to set the second arguement, the number argument I get an error which will say something like this:
Failed to convert parameter value from
a Decimal to a DateTime
While if I enter it parameterless, i.e hardcode an Int, it works fine.
This works:
SELECT FieldOne, DateField
FROM Table
WHERE (DateField> DATEADD(day, -10, GETDATE()))
while this does not:
SELECT FieldOne, DateField
FROM Table
WHERE (DateField> DATEADD(day, #days, GETDATE()))
Where #days = -10
Any ideas into what I am doing wrong? Incidentally I am setting this variable in SQL Server Manager, as I am trying to work out a bug in my DataAccess code. Not sure if that makes a difference.
Thanks

I know this is an old post, but for anyone else having this problem I had a similar issue in Reporting Services 2008 R2, although the error message was "Argument data type nvarchar is invalid for argument 2 of dateadd function." I think this issue could be related.
The problem was caused by the way Reporting Services parses the SQL code to generate a report dataset. In my case, I was able to change this dataset query:
SELECT DateAdd(wk, #NumWeeks, calendar_date) AS ToWeekFromDate
FROM dim_date
to this:
SELECT DateAdd(wk, Convert(Int, #NumWeeks), calendar_date) AS ToWeekFromDate
FROM dim_date
and the error was resolved.
EDIT: Just to expand on this answer a little: the issue was that Reporting Services was unable to parse the correct data type for #NumWeeks, I think possibly due to it being inside the DateAdd() function, and was defaulting it to NVarchar. Adding an explicit Convert() to set the data type to Int (even though it was already a number) enabled the parser to correctly identify the data type for #NumWeeks.

It sounds like you're passing the decimal as the 3rd instead of the 2nd parameter to DATEADD(), like:
DATEADD(day, GETDATE(), #days)
Although the snippet in the question looks fine.
(For extra clarity, the snippet above is an error. This is the code that would generate the error from the question.)

The following code works perfectly fine here (SQL Server 2005, executed in Management Studio):
DECLARE #days decimal
SET #days = -10
SELECT DATEADD(day, #days, GETDATE())
as does the following
DECLARE #days decimal
SET #days = -10
SELECT * FROM myTable WHERE myDate > DATEADD(day, #days, GETDATE())
So, the problem must lie somewhere else...

Are you sure the error is associated with this statement? There are no decimals involved and if I try this it still works
DECLARE #days decimal (19,6)
SET #days = -10.3346
--result is actually irrelevant
IF CAST(40000.6 AS decimal (19,6)) > DATEADD(day, #days, GETDATE())
SELECT 'yes'
ELSE
SELECT 'no'
Even trying to cast -10 decimal to smalldatetime this gives a different error
SELECT CAST(CAST(-10 AS decimal (19,6)) AS smalldatetime)
Msg 8115, Level 16, State 2, Line 1
Arithmetic overflow error converting expression to data type smalldatetime.

Related

Same code errors in a Stored Procedure, works in T-SQL

I have a stored procedure that calls a linked server like below. The column 'datestr' is of type char(8) and is not always properly formatted. It is usually yyyymmdd but since I do not control how that data is formatted, I am using the TRY_CAST to only get rows where I can format it into a date.
Executing the SP gives me the following 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.
Running the exact same code extracted from the SP in T-SQL returns data without error. I'm certain the issue is with the part of the WHERE clause with the DATEADD function hitting a value that is not able to be CAST into a date but I can't figure out why it runs differently in SP and extracted T-SQL.
I checked the plan using SET SHOWPLAN_ALL ON before running both and see some variations. Namely the estimated rows in the working query are much lower in the Remote Query operator (~200K vs. 15 mil)
CREATE Procedure [dbo].[SampleSP]
AS
SELECT top 50 tbl1.rowID as rowID,
year(datestr) as [year],
month(datestr) as [month],
count(*) AS CountRow
FROM [LinkedSer].[RemoteDB].[dbo].[tbl1] tbl1
inner join [dbo].[LocalTbl] tbl2 on tbl1.rowID = tbl2.rowID
WHERE tbl1.row_type = 'tbl1A'
and (TRY_CAST(tbl1.datestr AS date) IS NOT NULL
and tbl1.datestr > DATEADD(yy, -10, getdate()))
group BY tbl1.rowID, year(tbl1.datestr), month(tbl1.datestr)
The order the predicates are evaluated is plan-dependent. So you need to eliminate the potentially-invalid comparison from your code.
And simplifying to:
and TRY_CAST(tbl1.datestr AS date) > DATEADD(yy, -10, getdate())
should do the trick.

Date conversion error in SQL on one Computer, but the code works on another?

I have this piece of Code
Select * FROM [DB].[dbo].[STG_TABLE]
WHERE convert(datetime, cast([CHANGE_DATE] as char(8))) > DATEADD(DAY, -3, GETDATE())
The CHANGE_DATE is of type numeric(8,0).
I have used this code before. It still works on my local machine on the same data, but when I run this on the Development server, it gives an error:
Conversion failed when converting date and/or time from character string.
Both computers has the same system date settings in the Control panel.
If I remove the convert, like so:
Select * FROM [DB].[dbo].[STG_TABLE]
WHERE cast([CHANGE_DATE] as char(8)) > DATEADD(DAY, -3, GETDATE())
it gives the same error which leads me to believe it is after the greater than, but I still don't know why.
Try another convert.
Select * FROM [DB].[dbo].[STG_TABLE]
WHERE [CHANGE_DATE] > cast(convert(char(8),DATEADD(DAY, -3, GETDATE()),112) as numeric(8,0))
GetDate() -> CHAR(8) -> NUMERIC and then compare to table field
Also try to check dates in your table
SELECT [CHANGE_DATE]
from [DB].[dbo].[STG_TABLE]
where isdate(cast([CHANGE_DATE] as char(8)))=0

Need help on DateTime Conversion in Sql Server 2005

I am facing problem in DateTime converstion.
My input is 09/22/2011, I need to convert into 20110922.
I tried the below one, but failed.
Select CONVERT(VARCHAR(8),'09/22/2011' , 112) as DateConv
Here you go:
SET DATEFORMAT mdy
SELECT CONVERT(VARCHAR(8), CAST('09/22/2011' as DATETIME) , 112) AS DateConv
If your input is actually a dateTime variable like you said (but didn't show in your code example), you can simplify this down to:
SELECT CONVERT(VARCHAR(8), #myDate , 112) AS DateConv
This will do the trick:
select year('09/22/2011') * 10000 + month('09/22/2011') * 100 + day('09/22/2011')
Without any other information, SQL is interpreting the '09/22/2011' as a varchar already, and just passes the data through (ignoring CONVERT's style argument). If you use the following line:
SELECT CONVERT (VARCHAR (8), CAST ('09/22/2011' as DATETIME), 112) as DateConv
it should work as expected since it will then view the '09/22/2011' as a date value. If you were getting the date from a column in a table, it would already know the type and you will not need to worry about the CAST portion of the expression, just use the column name.

SQL Server function to return minimum date (January 1, 1753)

I am looking for a SQL Server function to return the minimum value for datetime, namely January 1, 1753. I'd rather not hardcode that date value into my script.
Does anything like that exist? (For comparison, in C#, I could just do DateTime.MinValue)
Or would I have to write this myself?
I am using Microsoft SQL Server 2008 Express.
You could write a User Defined Function that returns the min date value like this:
select cast(-53690 as datetime)
Then use that function in your scripts, and if you ever need to change it, there is only one place to do that.
Alternately, you could use this query if you prefer it for better readability:
select cast('1753-1-1' as datetime)
Example Function
create function dbo.DateTimeMinValue()
returns datetime as
begin
return (select cast(-53690 as datetime))
end
Usage
select dbo.DateTimeMinValue() as DateTimeMinValue
DateTimeMinValue
-----------------------
1753-01-01 00:00:00.000
Have you seen the SqlDateTime object? use SqlDateTime.MinValue to get your minimum date (Jan 1 1753).
As I can not comment on the accepted answer due to insufficeint reputation points my comment comes as a reply.
using the select cast('1753-1-1' as datetime) is due to fail if run on a database with regional settings not accepting a datestring of YYYY-MM-DD format.
Instead use the select cast(-53690 as datetime) or a Convert with specified datetime format.
Enter the date as a native value 'yyyymmdd' to avoid regional issues:
select cast('17530101' as datetime)
Yes, it would be great if TSQL had MinDate() = '00010101', but no such luck.
Here is a fast and highly readable way to get the min date value
Note: This is a Deterministic Function, so to improve performance further we might as well apply WITH SCHEMABINDING to the return value.
Create a function
CREATE FUNCTION MinDate()
RETURNS DATETIME WITH SCHEMABINDING
AS
BEGIN
RETURN CONVERT(DATETIME, -53690)
END
Call the function
dbo.MinDate()
Example 1
PRINT dbo.MinDate()
Example 2
PRINT 'The minimimum date allowed in an SQL database is ' + CONVERT(VARCHAR(MAX), dbo.MinDate())
Example 3
SELECT * FROM Table WHERE DateValue > dbo.MinDate()
Example 4
SELECT dbo.MinDate() AS MinDate
Example 5
DECLARE #MinDate AS DATETIME = dbo.MinDate()
SELECT #MinDate AS MinDate
It's not January 1, 1753 but select cast('' as datetime) wich reveals: 1900-01-01 00:00:00.000 gives the default value by SQL server.
(Looks more uninitialized to me anyway)
This is what I use to get the minimum date in SQL Server. Please note that it is globalisation friendly:
CREATE FUNCTION [dbo].[DateTimeMinValue]()
RETURNS datetime
AS
BEGIN
RETURN (SELECT
CAST('17530101' AS datetime))
END
Call using:
SELECT [dbo].[DateTimeMinValue]()
What about the following?
declare #dateTimeMin as DATETIME = datefromparts(1753, 1, 1);
select #dateTimeMin;
The range for datetime will not change, as that would break backward compatibility. So you can hard code it.

Sql Server string to date conversion

I want to convert a string like this:
'10/15/2008 10:06:32 PM'
into the equivalent DATETIME value in Sql Server.
In Oracle, I would say this:
TO_DATE('10/15/2008 10:06:32 PM','MM/DD/YYYY HH:MI:SS AM')
This question implies that I must parse the string into one of the standard formats, and then convert using one of those codes. That seems ludicrous for such a mundane operation. Is there an easier way?
Try this
Cast('7/7/2011' as datetime)
and
Convert(DATETIME, '7/7/2011', 101)
See CAST and CONVERT (Transact-SQL) for more details.
Run this through your query processor. It formats dates and/or times like so and one of these should give you what you're looking for. It wont be hard to adapt:
Declare #d datetime
select #d = getdate()
select #d as OriginalDate,
convert(varchar,#d,100) as ConvertedDate,
100 as FormatValue,
'mon dd yyyy hh:miAM (or PM)' as OutputFormat
union all
select #d,convert(varchar,#d,101),101,'mm/dd/yy'
union all
select #d,convert(varchar,#d,102),102,'yy.mm.dd'
union all
select #d,convert(varchar,#d,103),103,'dd/mm/yy'
union all
select #d,convert(varchar,#d,104),104,'dd.mm.yy'
union all
select #d,convert(varchar,#d,105),105,'dd-mm-yy'
union all
select #d,convert(varchar,#d,106),106,'dd mon yy'
union all
select #d,convert(varchar,#d,107),107,'Mon dd, yy'
union all
select #d,convert(varchar,#d,108),108,'hh:mm:ss'
union all
select #d,convert(varchar,#d,109),109,'mon dd yyyy hh:mi:ss:mmmAM (or PM)'
union all
select #d,convert(varchar,#d,110),110,'mm-dd-yy'
union all
select #d,convert(varchar,#d,111),111,'yy/mm/dd'
union all
select #d,convert(varchar,#d,12),12,'yymmdd'
union all
select #d,convert(varchar,#d,112),112,'yyyymmdd'
union all
select #d,convert(varchar,#d,113),113,'dd mon yyyy hh:mm:ss:mmm(24h)'
union all
select #d,convert(varchar,#d,114),114,'hh:mi:ss:mmm(24h)'
union all
select #d,convert(varchar,#d,120),120,'yyyy-mm-dd hh:mi:ss(24h)'
union all
select #d,convert(varchar,#d,121),121,'yyyy-mm-dd hh:mi:ss.mmm(24h)'
union all
select #d,convert(varchar,#d,126),126,'yyyy-mm-dd Thh:mm:ss:mmm(no spaces)'
In SQL Server Denali, you will be able to do something that approaches what you're looking for. But you still can't just pass any arbitrarily defined wacky date string and expect SQL Server to accommodate. Here is one example using something you posted in your own answer. The FORMAT() function and can also accept locales as an optional argument - it is based on .Net's format, so most if not all of the token formats you'd expect to see will be there.
DECLARE #d DATETIME = '2008-10-13 18:45:19';
-- returns Oct-13/2008 18:45:19:
SELECT FORMAT(#d, N'MMM-dd/yyyy HH:mm:ss');
-- returns NULL if the conversion fails:
SELECT TRY_PARSE(FORMAT(#d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);
-- returns an error if the conversion fails:
SELECT PARSE(FORMAT(#d, N'MMM-dd/yyyy HH:mm:ss') AS DATETIME);
I strongly encourage you to take more control and sanitize your date inputs. The days of letting people type dates using whatever format they want into a freetext form field should be way behind us by now. If someone enters 8/9/2011 is that August 9th or September 8th? If you make them pick a date on a calendar control, then the app can control the format. No matter how much you try to predict your users' behavior, they'll always figure out a dumber way to enter a date that you didn't plan for.
Until Denali, though, I think that #Ovidiu has the best advice so far... this can be made fairly trivial by implementing your own CLR function. Then you can write a case/switch for as many wacky non-standard formats as you want.
UPDATE for #dhergert:
SELECT TRY_PARSE('10/15/2008 10:06:32 PM' AS DATETIME USING 'en-us');
SELECT TRY_PARSE('15/10/2008 10:06:32 PM' AS DATETIME USING 'en-gb');
Results:
2008-10-15 22:06:32.000
2008-10-15 22:06:32.000
You still need to have that other crucial piece of information first. You can't use native T-SQL to determine whether 6/9/2012 is June 9th or September 6th.
SQL Server (2005, 2000, 7.0) does not have any flexible, or even non-flexible, way of taking an arbitrarily structured datetime in string format and converting it to the datetime data type.
By "arbitrarily", I mean "a form that the person who wrote it, though perhaps not you or I or someone on the other side of the planet, would consider to be intuitive and completely obvious." Frankly, I'm not sure there is any such algorithm.
Use this:
SELECT convert(datetime, '2018-10-25 20:44:11.500', 121) -- yyyy-mm-dd hh:mm:ss.mmm
And refer to the table in the official documentation for the conversion codes.
For this problem the best solution I use is to have a CLR function in Sql Server 2005 that uses one of DateTime.Parse or ParseExact function to return the DateTime value with a specified format.
Short answer:
SELECT convert(date, '10/15/2011 00:00:00', 101) as [MM/dd/YYYY]
Other date formats can be found at SQL Server Helper > SQL Server Date Formats
Took me a minute to figure this out so here it is in case it might help someone:
In SQL Server 2012 and better you can use this function:
SELECT DATEFROMPARTS(2013, 8, 19);
Here's how I ended up extracting the parts of the date to put into this function:
select
DATEFROMPARTS(right(cms.projectedInstallDate,4),left(cms.ProjectedInstallDate,2),right( left(cms.ProjectedInstallDate,5),2)) as 'dateFromParts'
from MyTable
The most upvoted answer here are guravg's and Taptronic's. However, there's one contribution I'd like to make.
The specific format number they showed from 0 to 131 may vary depending on your use-case (see full number list here), the input number can be a nondeterministic one, which means that the expected result date isn't consistent from one SQL SERVER INSTANCE to another, avoid using the cast a string approach for the same reason.
Starting with SQL Server 2005 and its compatibility level of 90,
implicit date conversions became nondeterministic. Date conversions
became dependent on SET LANGUAGE and SET DATEFORMAT starting with
level 90.
Non deterministic values are 0-100, 106, 107, 109, 113, 130. which may result in errors.
The best option is to stick to a deterministic setting, my current preference are ISO formats (12, 112, 23, 126), as they seem to be the most standard for IT people use cases.
Convert(varchar(30), '210510', 12) -- yymmdd
Convert(varchar(30), '20210510', 112) -- yyyymmdd
Convert(varchar(30), '2021-05-10', 23) -- yyyy-mm-dd
Convert(varchar(30), '2021-05-10T17:01:33.777', 126) -- yyyy-mm-ddThh:mi:ss.mmm (no spaces)
This page has some references for all of the specified datetime conversions available to the CONVERT function. If your values don't fall into one of the acceptable patterns, then I think the best thing is to go the ParseExact route.
Personally if your dealing with arbitrary or totally off the wall formats, provided you know what they are ahead of time or are going to be then simply use regexp to pull the sections of the date you want and form a valid date/datetime component.
If you want SQL Server to try and figure it out, just use CAST
CAST('whatever' AS datetime)
However that is a bad idea in general. There are issues with international dates that would come up. So as you've found, to avoid those issues, you want to use the ODBC canonical format of the date. That is format number 120, 20 is the format for just two digit years.
I don't think SQL Server has a built-in function that allows you to provide a user given format. You can write your own and might even find one if you search online.
convert string to datetime in MSSQL implicitly
create table tmp
(
ENTRYDATETIME datetime
);
insert into tmp (ENTRYDATETIME) values (getdate());
insert into tmp (ENTRYDATETIME) values ('20190101'); --convert string 'yyyymmdd' to datetime
select * from tmp where ENTRYDATETIME > '20190925' --yyyymmdd
select * from tmp where ENTRYDATETIME > '20190925 12:11:09.555'--yyyymmdd HH:MIN:SS:MS
You can easily achieve this by using this code.
SELECT Convert(datetime, Convert(varchar(30),'10/15/2008 10:06:32 PM',102),102)
This code solve my problem :
convert(date,YOUR_DATE,104)
If you are using timestamp you can you the below code :
convert(datetime,YOUR_DATE,104)
dateadd(day,0,'10/15/2008 10:06:32 PM')

Resources