Use a report parameter instead of GETDATE in stored procedure - sql-server

I have a SQL query which is saved as a stored procedure. I am using three different stored procedures to go back 1, 2, or 3 days depending on today's date. This makes it possible for my dashboard users to go back and skip weekends when comparing stats. This actually works. It looks at todays date and if it is Sunday go back 2 days, if it is Monday go back 3 days otherwise go back 1 day. The dashboard is created in Report Builder. Below is shown the between dates if today is Sunday (i.e. skip 2 days and go back to Friday which is the last normal working day). So much for the background. My challenge is now the user of the dashboard would like a BeginDate and EndDate date picker parameter in the report so I can no longer use these hard coded date strings but will have to incorporate a parameter into them. How do I replace a parameter say called #BeginDate in the following line where it says "GETDATE()":
BETWEEN DATEADD(DAY, -2, DATEADD(DAY, DATEDIFF(DAY,0,GETDATE()), 0))
AND DATEADD(SECOND, -86401, DATEADD(DAY, DATEDIFF(DAY,0,GETDATE()),0))
And based upon the date the end user selects then go and use one of the three stored procedures. I think I can make this work somehow, but I cannot figure out how to replace GETDATE() above with a parameter entered in by the user. If I just replace it with a parameter it throws back an error. I'm sure there is a really smart way of doing this. I'm still looking!!!

If you are passing a new parameter into the stored prcoedure:
BETWEEN DATEADD(DAY, -2, #BEGINDATE) AND DATEADD(SECOND, -86401, #BEGINDATE)
Adding seconds seems unnecessarily complicated:
>= DATEADD(DAY, -2, #BEGINDATE) and XXX < DATEADD(DAY, -1, #BEGINDATE)

Related

SSRS How to define parameters as 7 days ago plus 1 hour

I have a report made using SSRS and SQL Server and I have set a StartDate and EndDate parameters for the report.
I have set the default value for StartDate as =DateAdd("D", -7, Today())
I have set the default value for EndDate as =DateAdd("H", 1, Today())
How can I add 1 hour to the StartDate Parameter?
I've tried
=DateAdd("H", 1, (DateAdd("D", -7, Today())))
Would that work? I'm currently testing it but the report usually takes 6 hours to run.
Do the date math in hours instead of days.
=DateAdd("H", -169, Today())
Would that work? You can always try that in SQL Server. The answer is yes :o)
Although, you should use the NOW() function instead of the TODAY() function (see the Update below).
SQL Server:
SELECT DATEADD(HH, 1, DATEADD(DD, -7, GETDATE()))
SSRS/VS:
DateAdd(DateInterval.Hour, -167, Now())
Update: To Larnu's point, Today() will default as a date format of MM/DD/YYYY. If you only subtract 167 hours from Today, then the field will show in date time, but the result will be incorrect as it will show 1:00 AM for the time. So use the NOW() function, instead of TODAY(). The result will be 167 hours from the current time and will be in the format of MM/DD/YYYY HH:MM:SS.
Also, you can make the change in the parameter field and click on the Preview in VS to see these changes. You would not need to run the report to see this change. That, or I do not understand what you are trying to accomplish.

Set report date for date other than today in SQL reporting

I have a report that I have been asked to produce. The first column of data is total time entered from the first of the year to the end of the previous month. The next column of data is total time from beginning of "current" month to the end of "current" month.
For example. If this report was being run for March then the first column would be total time for Jan and Feb and the second column would be total time for March. If I were to run it in April then the first column would be total time for Jan/Feb/Mar and the second column total time for April etc.
I am using various expressions to get first date of the year, last date of previous month, first date of this month, last date of this month. All working fine and it runs like a dream if you run the report in the current month (i.e. March) but if you want to run the report in April for March's data it won't do it as it's reading the date on the computer and using that to calculate the prev month.
In Crystal reports you can set a report date. Is there something similar in SQL reporting? I'm assuming you DECLARE the report date in your initial query but I haven't yet found the right combination of functions.
This report is for an external bit of software that we run.
The only parameters I can use are #FromDate and #ToDate and these are set as text rather than date
I was planning on using the #ToDate to set the report date but would obviously have to convert it from text first
Any guidance very much appreciated
Try this. You could actually do it without all the declare statements, I just did those to break it down to be easy to read.
declare #date_entered datetime = '2/7/2017'
declare #start_of_year datetime = DATEADD(yy, DATEDIFF(yy, 0, #date_entered), 0)
declare #start_of_month datetime = DATEADD(month, DATEDIFF(month, 0, #date_entered), 0)
declare #end_of_month datetime = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#date_entered)+1,0))
declare #end_of_last_month datetime = DATEADD(day,-1,#start_of_month)
-- Now remove weekends from days found
declare #amount_of_days_previous tinyint = datediff(day,#start_of_year,#end_of_last_month) - (datediff(wk, #start_of_year, #end_of_last_month) * 2)
declare #amount_of_days_this tinyint = DATEDIFF(day,#start_of_month,#end_of_month) - (datediff(wk, #start_of_month, #end_of_month) * 2)
select #amount_of_days_previous * 8 as WorkHoursinDaysPrevious,
#amount_of_days_this * 8 as WorkHoursinDaysThis
I had a think over the weekend and realised that I was approaching the problem all wrong. I was trying to set the report date so that my query could read that date and then go back and find the relevant date (first date in the year, last date of previous month etc).
What I needed to do was use my date criteria (FromDate and ToDate) in my DATEADD selections.
CONVERT(datetime,#FromDate,103) AS FIRSTDAYOFYEAR,
DATEADD(D, - 1, DATEADD(MONTH, DATEDIFF(MONTH, '19000101', CONVERT(datetime,#ToDate,103)), '19000101')) AS LASTDAYPREVMONTH,
DATEADD(MONTH,DATEDIFF(MONTH, '19000101',CONVERT(datetime,#ToDate,103)), '19000101') AS FIRSTDAYMONTH,
CONVERT(datetime,#ToDate,103) AS LASTDAYMONTH,
This is now much better because my "first date of year" can be anything the user wants, not just the first day of the year.

How do I use dateadd to get the first day of last year?

I'm trying to pull data that falls in between January 1st, 2014 and today's date last year (ie. August 3rd, 2014). How would I go about using ``dateadd` to get the date 1/1/14? I'm using the following code to get the date 8/3/14.
dateadd (yy, -1, getdate())
I want to avoid explicitly searching for 1/1/14 because in a year's time I'd like the sql query to find 1/1/15 without me having to go back in and rewrite it.
Use DATEFROMPARTS:
DATEFROMPARTS(YEAR(GETDATE()) - 1, 1, 1)
DATEADD(yy, DATEDIFF(yy,0,getdate())-1, 0)
DATEFROMPARTS() is the best way but it requires SQL2012 or later. If you're on an earlier vierion, try this:
You can use GETDATE() to get the current date
You can use the function YEAR() to extract the year from any date
Subtract 1 from it to get last year
Append 1/1/ to the front of it
Convert it back to a date again
select convert(datetime, '1/1/' + convert(varchar(max),year(getdate())-1))

TSQL: Date BETWEEN Query - Ignoring Time

I am trying to do a query between 2 dates. I would like to do it without having to worry about the time. When a user enters the 2 dates they want to search on, there is no selection for time. This means that the dates that they enter default to 12:00 AM.
The dates in the table do have times though. I just would like to ignore the times all together so the search brings back any records form said date range.
Here is my SQL:
TheDate BETWEEN #EnteredBeginDate AND #EnteredEndDate
So when a user does a range search between 8/6/2009 AND 9/9/2009 I want to return the records:
8/6/2009 11:33:02 AM
8/6/2009 11:39:17 AM
9/9/2009 8:21:30 AM
What's happening now is I only get back:
8/6/2009 11:33:02 AM
8/6/2009 11:39:17 AM
Can someone please recommend the best way to do this in SQL? I know how to do it in C#.
Just use DATEADD for the enddate to set it to midnight on the NEXT day...
TheDate BETWEEN #EnteredBeginDate AND DATEADD(day, 1, #EnteredEndDate)
If you want to be really precise, you could subtract a second or millisecond from that to make it 11:59:59 on your specified date:
TheDate BETWEEN #EnteredBeginDate AND DATEADD(second, -1, (DATEADD(day, 1, #EnteredEndDate)))
If you're on SQL Server 2008 or 2008 R2, you could use the new DATE datatype:
TheDate BETWEEN CAST(#EnteredBeginDate AS DATE) AND CAST(#EnteredEndDate AS DATE)
That strips off the time portion and looks only at the date
If you are using SQL Server 2008, then do this:
TheDate BETWEEN cast(#EnteredBeginDate as date) AND cast(#EnteredEndDate as date)
TheDate BETWEEN #EnteredBeginDate AND dateadd(day, 1, #EnteredEndDate)
If just the date is passed into SQL Server, it will make the time 12:00 AM. So, the end date on the the between clause is 9/9/2009 12:00 AM. Just add a day or modify the date passed into the query to include the correct time.

Getting today's midnight time as UTC

I have the following query which calculates today's midnight value (UTC) as a datetime:
SELECT CONVERT(DATE,GETDATE())+(GETDATE()-GETUTCDATE())
Result: 2011-11-03 19:00:00.000 (for GMT-5 on Nov. 4, 2011)
Not only that, but on occasion, it returns values like these:
2011-11-03 19:00:00.003
2011-11-03 19:00:00.007
2011-11-03 19:00:00.010
..., which are wrong!
There must be a better way to do this.
I already answered this with a solution using DATEADD and DATEDIFF with GETDATE() and GETUTCDATE(), similar to the example given in the original question, but since then I've discovered the datetimeoffset data type added in SQL Server 2008. This stores a datetime along with a timezone offset.
How you use this type will depend on whether you want to change the data type of your existing data. If you don't want to change anything, the following statement will return a datetime type with the local time of midnight:
SELECT CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset,
CONVERT(date, GETDATE())),
DATENAME(TzOffset, SYSDATETIMEOFFSET())))
You could also convert any UTC time into local time using:
SELECT CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset,
#myutctime,
DATENAME(TzOffset, SYSDATETIMEOFFSET())))
The datetimeoffset type is only available using SQL2008 and above. If you need to do this with 2005 and below, you can use a solution similar to the one in the original question, but altered to account for the fact that GETDATE() - GETUTCDATE() is not an atomic operation and will likely involve milliseconds of difference between when the two are executed.
SELECT DATEADD(minute,
DATEDIFF(minute, GETUTCDATE(), GETDATE()),
CONVERT(datetime, CONVERT(date, GETDATE())))
This will take the number minutes between GETDATE() and GETUTCDATE() and add them onto the local midnight time. Unfortunately, you have to convert back from date to datetime as DATEADD won't work with minutes if you give it a date. I'd suggest wrapping this into a user-defined function to make it look less verbose, e.g.
CREATE FUNCTION dbo.MidnightASUTC(#dt as datetime)
RETURNS datetime
AS
BEGIN
RETURN DATEADD(minute,
DATEDIFF(minute, GETUTCDATE(), GETDATE()),
CONVERT(datetime, CONVERT(date, #dt)))
END
SELECT dbo.MidnightAsUTC(GETDATE())
For a specific scenario like the one you've described ("today's midnight value (UTC) as a datetime"), a programmatic approach makes sense, but if you ever need to extend it to a different question (what was midnight UTC for this summer?), you may want to use a calendar table (to account for things like daylight savings time, etc).

Resources