I am trying to create dynamic code for date calculation in SQL stored procedures but am having problems executing string expressions and parameters as date expressions.
I want to hold generic string expressions in a table that will create the dates according to the value of the parameters.
for example this is a generic expression :
DATEADD(#TimeResolution, -#IterationN, #CurrentCalc)
as you can see these generic expressions are composed out of parameters to.
in the stored procedures I intend to declare the variables that are in the expression and assign values to them using a select statement from a different table.
the problem is that after deriving these string values and writing the expression it does not give me the date I want but fails.
so for example if I write the following code
declare #Today date
declare #LastYear date
set #Today = getdate()
set #LastYear = DATEADD(year, -1, #Today)
select #Lastyear
it works fine and I will get last year's date.
but when I try something like this :
declare #Today date
declare #LastYear date
declare #Timeresolution varchar(5)
select #Timeresolution = [Timeresolution] from dbo.mytable where rule_id=1//Timeresolution is a varchar column in my table holding the values 'year' or 'month'
declare Iteration int
select #Iteration = [Iteration] from dbo.mytable where rule_id=1 //Iteration is a int column in my table holding the values 1 or 2, or 3
set #Today = getdate()
set #LastYear = DATEADD(Timeresolution , -Iteration , #Today)
select #Lastyear
this gives me a conversion error.
Is there a way to create such dynamic date expressions?
It isn't possible to use a variable for the interval in DATEADD, but you can do something like this:
IF #Timeresolution = 'year'
BEGIN
SET #LastYear = DATEADD(year, -#Iteration , #Today)
END
IF #Timeresolution = 'month'
BEGIN
SET #LastYear = DATEADD(month, -#Iteration , #Today)
END
Related
Using string parameter for start date and end date. Passing this values to a sql task editor in SSIS. Wanted to convert the start date to day - 1 and end date to + 1 day and then process the variable. My actual code is as below:
DECLARE #P_StartDate VARCHAR(100)
DECLARE #P_EndDate VARCHAR(100)
SET #P_StartDate = ?
SET #P_EndDate = ?
IF (#P_StartDate!='' AND #P_EndDate!='')
BEGIN
SELECT #P_StartDate , #P_EndDate
END
Wanted to do the changes like below but this is not working. Please help.
DECLARE #P_StartDate VARCHAR(100)
DECLARE #P_EndDate VARCHAR(100)
SET #P_StartDate = ?
SET #P_EndDate = ?
#P_StartDate = DATEADD(day, -1, convert(date, max(#P_StartDate), 102)
#P_EndDate = DATEADD(day, 1, convert(date, max(#P_EndDate), 102)
IF (#P_StartDate!='' AND #P_EndDate!='')
BEGIN
SELECT #P_StartDate , #P_EndDate
END
Edit: I cannot use the variable as date type because i am using this string type variable to dynamically generate one big sql query inside another ssis variable. Can anyone please guide me if it is possible to achieve the same thing without using datetype variable.
Your script is ok, there is syntax error,
DECLARE #P_StartDate VARCHAR(100)
DECLARE #P_EndDate VARCHAR(100)
SET #P_StartDate = '2021-10-20'
SET #P_EndDate = '2021-10-30'
set #P_StartDate = DATEADD(day, -1, convert(date, #P_StartDate, 102))
set #P_EndDate = DATEADD(day, 1, convert(date, #P_EndDate, 102))
IF (#P_StartDate!='' AND #P_EndDate!='')
BEGIN
SELECT #P_StartDate , #P_EndDate
END
notice extra ")" here DATEADD(day, -1, convert(date, #P_StartDate, 102))
Why use max ?
Really this is not clear,what you are trying to do.
Edit: I cannot use the variable as date type because i am using this
string type variable to dynamically generate one big sql query inside
another ssis variable
On a table I have a bigint column that stores a timestamp with a microsecond precision like:
636453251396217655
636453251398405201
636453251592389899
636453251668326820
I have to build a script that, if that date is older than a week, the row must moved to another table.
I tried to convert to date using:
CREATE FUNCTION [dbo].[UNIXToDateTime] (#timestamp bigint)
RETURNS datetime
AS
BEGIN
DECLARE #ret datetime
SELECT #ret = DATEADD(second, #timestamp, '1970/01/01 00:00:00')
RETURN #ret
END
and used like:
select dbo.UNIXToDateTime(636453251396217655)
but because of the bigint my script crash because:
Arithmetic overflow error during expression conversion in int data
type
I can lose precision, the important is the date part that is the main part of the sql filter.
Demo: http://sqlfiddle.com/#!6/24f05/1
There's an answer here for converting with epoch values:
CREATE FUNCTION [dbo].[fn_EpochToDatetime] (#Epoch BIGINT)
RETURNS DATETIME
AS
BEGIN
DECLARE #Days AS INT, #MilliSeconds AS INT
SET #Days = #Epoch / (1000*60*60*24)
SET #MilliSeconds = #Epoch % (1000*60*60*24)
RETURN (SELECT DATEADD(MILLISECOND, #MilliSeconds, DATEADD(DAY, #Days, '1/1/1970')))
END;
You can use that function but simply divide your epoch values. As you are fine with the loss of fidelity, this will suit your needs perfectly. For example:
DECLARE #epoch BIGINT = 636453251396217655
SELECT dbo.[fn_EpochToDatetime](#epoch/100000)
I'm getting the error
Invalid parameter 1 specified for dateadd.
when I try to execute the following dynamic parametrized query in SQL Server 2012:
DECLARE #Interval nvarchar(5) = 'DAY'
DECLARE #Increment int = 10
DECLARE #BaseDate date = getdate()
DECLARE #ResultDate date
DECLARE #Query nvarchar(2000)
SET #Query = 'SELECT #result = DATEADD(#Interval, #Increment, CAST(#BaseDate AS DATE))'
EXECUTE sp_executesql #Query,
N'#result date OUTPUT, #Interval varchar(50), #Increment int, #BaseDate date',
#Interval = #Interval, #Increment = #Increment,
#BaseDate = #BaseDate, #result = #ResultDate OUTPUT
SELECT #ResultDate
I've changed the SET #Query line to this one.
SET #Query = 'SELECT #result = DATEADD(' + #Interval +', #Increment, CAST(#BaseDate AS DATE))'
Although it works fine, I'm curious about why the first statement is causing the error in my dynamic SQL query?. Doesn't sp_executesql generate the same statement than the concatenated query one?
So the way to think about parameterized dynamic sql is you can only use a parameter where you could if it were static SQL. DATEADD expects a special date part keyword (e.g. day, hour, year, etc), not a literal string, and not a variable. It's the same issue some people run into where they think they can parameterize something like a table name. The first statement fails because even in static sql, this is invalid:
declare #increment nvarchar(5) = 'day'
select dateadd(#increment, 1, getdate())
That's equivalent to
select dateadd('day', 1, getdate())
The second statement succeeds because you're concatenating the string "day" which gets evaluated to the keyword.
In the first case, the query (with #Interval expanded to its value) becomes this:
SELECT #result=DATEADD('DAY', #Increment, CAST(#BaseDate AS DATE))
and in the second query it becomes this:
SELECT #result=DATEADD(DAY, #Increment, CAST(#BaseDate AS DATE))
The first query is invalid because there the first parameter to DATEADD is a string value, where the compiler expects a language keyword, and those are not the same in SQL.
For more info, see here: https://learn.microsoft.com/en-us/sql/t-sql/functions/dateadd-transact-sql
Please note the line under datepart saying User-defined variable equivalents are not valid. In other words you can't put quotes around these "values", they are not strings but keywords, and they can not be put in variables.
The code select DATEPART(month,getutcdate()) returns an integer representing the numeric month value of the current date.
The value MONTH is one of a number of predefined options for the interval parameter.
What is the underlying data type of that interval value?
declare #date datetime = getutcdate()
, #interval notNVarChar(16) = 'month' --what type should this be?
--Would it need quotes for assignment?
select DATEPART(#interval, #date)
You can make it parameterize by making a dynamic SQL as below:
declare #date datetime
set #date = GETDATE()
declare #option varchar(50)
declare #sql varchar(max)
SET #option = 'MONTH' --Here you can set other options like hour, second, milisecond etc..
set #sql = 'SELECT DATEPART('+ #option + ',''' + CONVERT(varchar,#date,21)+''')'
print #sql
EXEC( #sql)
There isn't one - you cannot parameterize it.
From the documentation:
DATEPART ( datepart , date )
datepart
Is the part of date (a date or time value) for which an integer will be returned. The following table lists all valid datepart arguments. User-defined variable equivalents are not valid.
(my emphasis)
There are lots of options available like :
day
week
hour
minute
second
millisecond
etc..
PLease go thru thisLINK
SELECT * FROM TABLE
WHERE YEAR(MDTFlgtStart)=YEAR(GETDATE()) AND MONTH(MDTFlgtStart)=MONTH(GETDATE())
Above code it compares with present year and month with the column year and month.
But do we have any chance we can give year=2012 month =3
or year =2011 month=5
You could declare variables:
DECLARE #YEAR AS INT
DECLARE #MONTH AS INT
SET #YEAR = 2012
SET #MONTH = 3
SELECT *
FROM TABLE
WHERE YEAR(MDTFlgtStart)=#YEAR AND MONTH(MDTFlgtStart)=#MONTH
You can wrap the above in a procedure for re-usability....
You can just use parameters for those values. As a bonus, avoiding functions against the column will help assist a seek if an index exists on the column (of course SELECT * means it will likely end up as a full scan anyway, or a range scan and a bunch of lookups)...
-- these would be input parameters for your stored procedure
DECLARE #y INT = 2011, #m INT = 5;
-- now have a date variable:
DECLARE #dt DATE = DATEADD(MONTH, #m-1, DATEADD(YEAR, #y-1900, 0));
SELECT ... FROM dbo.tablename
WHERE MDTFlgtStart >= #dt
AND MDTFlgtStart < DATEADD(MONTH, 1, #dt);
Also you should stop inviting whoever named these columns to lunch, because I have to assume they're not very nice.