How can I obtain the date of 2 Fridays ago and 2 Saturdays ago (SQL Server 2012+)
For example,
if run today, Monday Oct 12, my query should result in Sat Oct 3 and Friday Oct 9
if run on Tuesday Oct 20, my dates should be Sat Sat Oct 10 and Friday Oct 16
I am looking for an answer like select xyz getdate() ....
#Andresbi, your examples states 2 Saturdays before and 1 Friday before.
I think this code gives you the result:
declare #dt datetime = '20201020'
select
(
/* Previous sunday */
#dt - datepart(dw, #dt) + 1
/* Previous saturday */
- 1
/* and the saturday before */
- 7
),
(
/* Previous sunday */
#dt - datepart(dw, #dt) + 1
/* Previous friday */
- 2
)
select dateadd(day, -08, dateadd(wk, datediff(wk, 0, getdate()), 0))
select dateadd(day, -10, dateadd(wk, datediff(wk, 0, getdate()), 0))
Related
Using SQL Server 2008 R2, I've written some code to produce an aggregate results table that calculates the average wait time (from referral to appointment date) for all appointments within the month.
Based on whatever day the query is run, I want it to produce me a table of results for the previous 12 full months, excluding the current month. So for example, if I run the query today (6th Sept 2017), I want the table of results to give me 12 rows for the months August 2017 back to Sept 2016, like this:
YEAR | MONTH | MONTHNAME | AVG DAYS WAIT
-----+-------+-----------+---------------
2017 | 8 | August | 42
2017 | 7 | July | 43
2017 | 6 | June | 47
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2016 | 9 | September | 42
I'm using the following code which does indeed return me a 12 month list and excludes the current month:
SELECT
year (OP.Appointment_Date) [Year]
,month (OP.Appointment_Date) [Month]
,DATENAME (month,OP.Appointment_Date) [MonthName]
,AVG(DATEDIFF (dd,OP.Received_Date,Appointment_Date)) [Avg Days Wait]
FROM
[HDM_Local].[Outpatients].[vw_OP_Appointments] OP WITH (NOLOCK)
WHERE
OP.Appointment_Date >= DATEADD(month, -12, GETDATE())
AND OP.Appointment_Date < DATEADD(month, -1, GETDATE())
GROUP BY
year(OP.Appointment_Date)
,month(OP.Appointment_Date)
,DATENAME(month,OP.Appointment_Date)
ORDER BY
year(OP.Appointment_Date)desc
,month(OP.Appointment_Date)desc
However, the problem I've found is that the result for the most recent month (August) is incorrect.
I know from validating my data that the average wait time in August was 42 days. The query above is actually giving me a figure of 50.
I'm presuming that what's happening is the AND OP.Appointment_Date < DATEADD(month, -1, GETDATE()) statement is taking today's date, subtracting a full month's worth of days from it, and then calculating the average wait time for appointments in August based only on those appointments dated between 1st-6th August (or something along these lines).
The same issue also appears to be influencing the result for the oldest month in the list, I presume again because it's ignoring the first 5/6 days during Sept 2016 when performing the calculation.
Please can anyone explain how to code the statement to effectively "ignore the current month and return the previous 12 months, based on the full range of dates within each month"?
Your where clause is subtracting months, but is not truncating to the start of each month.
This will give you the range that starts from the first day of the month 12 months ago through the end of last month:
where op.Appointment_Date >= dateadd(month, datediff(month, 0, getdate() )-12, 0)
and op.Appointment_Date < dateadd(month, datediff(month, 0, getdate() ), 0)
Here is a comparison of your date range, vs a truncated to month date range:
select
TruncatedToMonth = 'N'
, fromdate = dateadd(month, -12, getdate())
, thrudate = dateadd(month, -1, getdate())
union all
select
TruncatedToMonth = 'Y'
, fromdate = dateadd(month, datediff(month, 0, getdate() )-12, 0)
, thrudate = dateadd(month, datediff(month, 0, getdate() ), 0)
rextester demo: http://rextester.com/RGJ79943
returns:
+------------------+---------------------+---------------------+
| TruncatedToMonth | fromdate | thrudate |
+------------------+---------------------+---------------------+
| N | 2016-09-06 14:38:07 | 2017-08-06 14:38:07 |
| Y | 2016-09-01 00:00:00 | 2017-09-01 00:00:00 |
+------------------+---------------------+---------------------+
WHERE
OP.Appointment_Date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0)
AND OP.Appointment_Date < DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1)
--or --
WHERE
OP.Appointment_Date between DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1)
Basically:
select DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) --First day of previous month
select DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) --Last Day of previous month
I would personally remove your logic from the where clause and place them into a variable since they do not rely on columns (will reduce your overhead either a negligible amount or substantial, depending on your database).
Try these variables in your where clause, should return beginning of September 2016 to end of August 2017
DECLARE #MinDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) -- Get start of month 13 months before current
DECLARE #MaxDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), -1) -- Get end of latest month before current
SELECT #MinDate, #MaxDate
EDIT: Just re-reading your post. The way that DATEADD MONTH works, is to literally add or subtract that number of months from the date i.e. if it is the 6th September 2017, take 12 months from that which returns the 6th September 2016. You can always take clauses like that out of your WHERE clause and place them into a select to see the effect they're having i.e.:
SELECT DATEADD(month, -12, GETDATE()), DATEADD(month, -1, GETDATE())
Returning
(No column name) (No column name)
2016-09-06 18:45:07.857 2017-08-06 18:45:07.857
I have to get/create date from the user input of week of month (week number in that month - 1st,2nd,3rd,4th and last) and day of week (sunday,monday..) in SQL server.
Examples:
4th Sunday of every month, Last Friday of every month, First Monday etc.
I was able to do it easily in .net but SQL server does seem limited in the date functions.
I am having to use lot of logic to get the date. To calculate the date using the above two parameters I had to use lot of datepart function.
Any suggestions on how to come up with the optimal SQL query for such a function?
I created a function other day for another OP GET Month, Quarter based on Work Week number
This function takes the current year as default it can be further modified to take Year as a parameter too.
an extension to that function can produce the results you are looking for ....
WITH X AS
(
SELECT TOP (CASE WHEN YEAR(GETDATE()) % 4 = 0 THEN 366 ELSE 365 END)-- to handle leap year
DATEADD(DAY
,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1
, CAST(YEAR(GETDATE()) AS VARCHAR(4)) + '0101' )
DayNumber
From master..spt_values
),DatesData AS(
SELECT DayNumber [Date]
,DATEPART(WEEKDAY,DayNumber) DayOfTheWeek
,DATEDIFF(WEEK,
DATEADD(WEEK,
DATEDIFF(WEEK, 0, DATEADD(MONTH,
DATEDIFF(MONTH, 0, DayNumber), 0)), 0)
, DayNumber- 1) + 1 WeekOfTheMonth
FROM X )
SELECT * FROM DatesData
WHERE DayOfTheWeek = 6 -- A function would expect these two parameters
AND WeekOfTheMonth = 4 -- #DayOfTheWeek and #WeekOfTheMonth
Here is a general formula:
declare #month as datetime --set to the first day of the month you wish to use
declare #week as int --1st, 2nd, 3rd...
declare #day as int --Day of the week (1=sunday, 2=monday...)
--Second monday in August 2015
set #month = '8/1/2015'
set #week = 2
set #day = 2
select dateadd(
day,
((7+#day) - datepart(weekday, #month)) % 7 + 7 * (#week-1),
#month
)
You can also find the last, 2nd to last... etc with this reverse formula:
--Second to last monday in August 2015
set #month = '8/1/2015'
set #week = 2
set #day = 2
select
dateadd(
day,
-((7+datepart(weekday, dateadd(month,1,#month)-1)-#day)) % 7 - 7 * (#week-1),
dateadd(month,1,#month)-1
)
This is how the July month looks like.
I am trying to pick the current week in current month with getdate() parameter using the below code.
declare #date datetime = getdate()
select datepart(day, datediff(day, 0, #date) / 7 * 7) / 7 + 1
Expecting the result as
Date -> week Number
2015-07-01 -> 1
2015-07-06 -> 2
2015-07-13 -> 3
But, instead, the result is:
Date -> week Number
2015-07-01 -> 5
2015-07-06 -> 1
2015-07-13 -> 2
How do I get the first format in SQL Server?
Thanks in advance
This seems to get the right answer
select datediff(week, dateadd(week, datediff(week, 0, dateadd(month, datediff(month, 0, #date), 0)), 0), #date)+1
I have a complicated calendar report coming from a SQL query where I have the year, month and WeekNumOfMonth (meaning the week number from the beginning of the month).
I need a function to return the DayOfMonth (ie: values of between 1-28,29,30 or 31 depending on the month) given Year, month and WeekNumOfMonth.
I have seen functions that do this given WeekNum from beginning of year but I only have WeekNum of the given month. I just can't seem to give the datePart and dateAdd functions right. Any help would be appreciated.
Note : Combination of Year ,Month ,Week Number will not give you the
day name because a week contain more than one day so how can you find
which day is it ? it is not possible
example : year 2015 month 06 week number 1
then it has a combination of
1 monday
2 tuesday
3 wednesday
4 thursday
5 friday
6 saturday
then with these results how can you predit the exact day ??
Else need some conditions or restrictions
If you have Year, Month , and date then you can find the day name using the below query it will give the start and end date of the week then you can take the dates from start date and end with end date
SELECT (
DATENAME(dw,
CAST(DATEPART(m, GETDATE()) AS VARCHAR)
+ '/'
+ CAST(DATEPART(d, '2015-06-23') AS VARCHAR)
+ '/'
+ CAST(DATEPART(yy, getdate()) AS VARCHAR))
)
Update
If you need all days between the current week then use the following query
DECLARE
#Year INT,
#Week INT,
#FirstDayOfYear DATETIME,
#FirstMondayOfYear DATETIME,
#StartDate DATETIME,
#EndDate DATETIME
SET #Year = 2015
SET #Week = 24// week number is based on year and it is not based on month
-- Get the first day of the provided year.
SET #FirstDayOfYear = CAST('1/1/' + CAST(#YEAR AS VARCHAR) AS DATETIME)
-- Get the first monday of the year, then add the number of weeks.
SET #FirstMondayOfYear = DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(DAY, 6 - DATEPART(DAY, #FirstDayOfYear), #FirstDayOfYear)), 0)
SET #StartDate = DATEADD(WEEK, #Week - 1, #FirstMondayOfYear)
-- Set the end date to one week past the start date.
SET #EndDate = DATEADD(WEEK, 1, #StartDate)
SELECT #StartDate AS StartDate, DATEADD(SECOND, -1, #EndDate) AS EndDate
Update
if do not have the year week number then use the below query
DATEPART(WEEK,'2015-06-01')
The above query is one example
In the query you have two values that is Year and Month
you need only the third value that means date
as a technique you can give 01 as the date then it will give the
starting week number your selected month
here it will result 23 so you got the idea in 2015 - month 06 starts with week number 23 so then you can easily do your stuff
Idea : if your week number is 1 then take 23 as week if it is 2 then 24 like wise..
Looking for a SQL query/queries that would determine the start day (Monday) of the current week.
Example:
If today is -> then the start of the week is
Sat Oct 09, 2010 -> Start of the week is Monday Oct 04, 2010
Sun Oct 10, 2010 -> Start of the week is Monday Oct 04, 2010
Mon Oct 11, 2010 -> Start of the week is Monday Oct 11, 2010
Tue Oct 12, 2010 -> Start of the week is Monday Oct 11, 2010
I have seen many "solutions" on Google and StackOverflow. The look something like:
SET #pInputDate = CONVERT(VARCHAR(10), #pInputDate, 111)
SELECT DATEADD(DD, 1 - DATEPART(DW, #pInputDate), #pInputDate)
This fails because:
Sun Oct 10, 2010 -> start of week Monday Oct 11, 2010 (which is incorrect).
Try using DATEFIRST to explicitly set the day of week to be regarded as the 'first'.
set DATEFIRST 1 --Monday
select DATEADD(DD, 1 - DATEPART(DW, #pInputDate), #pInputDate)
This will return the Monday of the week the InputDate falls in.
Building on top of p.campbell's solution, if you don't want to use or can't use "SET DATEFIRST 1", you can get around that by doing the following:
SELECT DATEADD(DD, 2 - DATEPART(DW, DATEADD(DD, -1, #pInputDate)), DATEADD(DD, -1, #pInputDate))
The most simple implementation
SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0) MondayOfCurrentWeek
You don't need to use DATEFIRST:
SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0) -- Monday of current week
SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()) - 1, 0) -- Monday of last week
SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()) + 1, 0) -- Monday of next week
SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0) + 4 -- Friday of current week
You need to use DATEFIRST. Without it your code always assigns Sunday to "wrong" week:
SELECT DATEADD(wk, DATEDIFF(wk,0,'2020-10-11'), 0) --> Sunday -> 2020-10-12
SELECT DATEADD(wk, DATEDIFF(wk,0,'2020-10-12'), 0) --> Monday -> 2020-10-12
SELECT DATEADD(wk, DATEDIFF(wk,0,'2020-10-18'), 0) --> Sunday -> 2020-10-19
In this case 2 factors needs to be taken care of:
##DATEFIRST value
What day your weeks starts on (for me it is Monday)
E.g.: all below lines produce 2020-10-12 (Monday for week starting on Monday, 2020-10-12 and ending on Sunday, 2020-10-18) regardless of ##DATEFIRST value:
SELECT DATEADD(DAY, -((##DATEFIRST + 7 - (2 - DATEPART(WEEKDAY, '2020-10-12')) % 7) % 7), '2020-10-12')
SELECT DATEADD(DAY, -((##DATEFIRST + 7 - (2 - DATEPART(WEEKDAY, '2020-10-13')) % 7) % 7), '2020-10-13')
SELECT DATEADD(DAY, -((##DATEFIRST + 7 - (2 - DATEPART(WEEKDAY, '2020-10-14')) % 7) % 7), '2020-10-14')
SELECT DATEADD(DAY, -((##DATEFIRST + 7 - (2 - DATEPART(WEEKDAY, '2020-10-15')) % 7) % 7), '2020-10-15')
SELECT DATEADD(DAY, -((##DATEFIRST + 7 - (2 - DATEPART(WEEKDAY, '2020-10-16')) % 7) % 7), '2020-10-16')
SELECT DATEADD(DAY, -((##DATEFIRST + 7 - (2 - DATEPART(WEEKDAY, '2020-10-17')) % 7) % 7), '2020-10-17')
SELECT DATEADD(DAY, -((##DATEFIRST + 7 - (2 - DATEPART(WEEKDAY, '2020-10-18')) % 7) % 7), '2020-10-18')