Can't understand this query - sql

declare #date varchar(30) = '2013-04-18'
DECLARE #WeekOfMonth TINYINT
SET #WeekOfMonth =
(
DAY(#DATE) +
(DATEPART(dw,
DATEADD (MONTH,
DATEDIFF (MONTH,
0,
#DATE),
0))
- 1) -1) / 7 + 1
print #WeekOfMonth
This is a query I found over the internet to find out week number of the month like it's '2013-03-04' today and this is second week of this month, Query is working fine, But I can't understand it and the person who has posted it over that blog haven't described it's working either. Can someone please help me to understand it better.

It's calculating the week number of the month, by adding the day number to the weekday number of the first day of that month, then divide by 7 and add 1. For example, with '2013-03-04', the day number is 4, the week number of '2013-03-01' is 6 (Friday), so the result is (4 + 6 - 1 - 1)/7 + 1 = 2.
Working from the inside out:
(DAY('2013-03-04') + (DATEPART(dw, DATEADD(MONTH, DATEDIFF(MONTH, 0, '2013-03-04'), 0)) - 1) - 1) / 7 + 1
Number of months from 1900-01-01, 1358
(DAY('2013-03-04') + (DATEPART(dw, DATEADD(MONTH, 1358, 0)) - 1) - 1) / 7 + 1
The date that is 1358 months from 1900-01-01, 2013-03-01
(DAY('2013-03-04') + (DATEPART(dw, '2013-03-01') - 1) - 1) / 7 + 1
Day of week of '2013-03-01', 6 (Friday)
(DAY('2013-03-04') + (6 - 1) - 1) / 7 + 1
The day part of '2013-03-04', 4
(4 + (6 - 1) - 1) / 7 + 1
-1 to convert Sunday = day 1 to Monday = day 1
(4 + 5 - 1) / 7 + 1
-1 because '2013-03-04' is 3 days from '2013-03-01'
= 2

Here is another way of looking at this:
You can run these statements to break it down yourself:
select datediff(month, 0, getdate()); -- Get Months since 1900-01-01
select DATEADD (MONTH, DATEDIFF (MONTH, 0, getdate()),0); -- Add Months back to 1900-01-01 to get 1st of Month (essentially stripping time and days)
select DATEPART(dw,DATEADD (MONTH, DATEDIFF (MONTH, 0, getdate()),0)-1); Get Day of Week Number for 1st of Current Month
select (day(getdate()) + DATEPART(dw,DATEADD (MONTH, DATEDIFF (MONTH, 0, getdate()),0)-1)-1); -- Add Day Number of Month for Current Date then subtract 1 to make it days, since we started on 1st
select (day(getdate()) + DATEPART(dw,DATEADD (MONTH, DATEDIFF (MONTH, 0, getdate()),0)-1)-1)/7; -- Determine how many whole weeks can be divided into this result
select (day(getdate()) + (DATEPART(dw,DATEADD (MONTH, DATEDIFF (MONTH, 0, getdate()),0))-1)-1)/7+1; -- We're zero indexed (meaning results would be zero in 1st week), so add 1 to get week number

Related

How to get max Saturday dates in a column of each month, without hardcoding

How to get max Saturday dates in a column of each month in SQL Server. Can someone please help me.
Now I need only the dates which has last Saturday of month.
For example,
The table has
07-08-2021 - Saturday
14-08-2021 - Saturday
21-08-2021 - Saturday
28-08-2021 - Saturday
04-09-2021 - Saturday
11-09-2021 - Saturday
18-09-2021 - Saturday
25-09-2021 - Saturday
Suppose we are in August month, I need to select last Saturday of that month( ONLY 28-08-2021)
Suppose we are in September month, I need to select last Saturday of that month( ONLY 25-09-2021)
Output:
28-08-2021
25-09-2021
assuming you have a datefield in your table (I will refer to it here as such in the below query)
with week as (
select
date_trunc('week', datefield + interval '2 day') - interval '2 day' as week_date
-- ^this adjusts the week date_trunc to start on Saturday (it starts on Monday by default)
from sometable
)
select
extract(month from week_date) as month_num,
max(week_date) as last_saturday
from week
group by month_num
note: if you only have partial data for the current month, this query will need to be altered slightly, but you didn't give me a lot to go off of here
A CTE is defined to populate the day name of entire month and then the requirement is filtered.
;with GetDates As (
select CAST('01-01-2021' as date) as StartDate, datename(dw, '09-01-2021') as Day_Name
UNION ALL
select DATEADD(day,1, StartDate), datename(dw, DATEADD(day,1, StartDate))
from GetDates
where StartDate < '09-30-2021'
)
select max(StartDate)
from GetDates where Day_Name = 'Saturday'
group by month(StartDate)
OPTION (MAXRECURSION 500)
Here is a function to calculate the Nth Weekday - which can calculate from the beginning of the month or from the end of the month.
Alter Function dbo.fnGetNthWeekDay (
#theDate datetime
, #theWeekday int
, #theNthDay int
)
Returns Table
As
Return
/*
Adapted from a version published by Peter Larrson - with minor modifications for performance
and restructured to eliminate usage of a derived table.
Inputs:
#theDate any date in the month
#theWeekday the weekday to calculate: 1 = Monday
2 = Tuesday
3 = Wednesday
4 = Thursday
5 = Friday
6 = Saturday
7 = Sunday
#theNthDay the week count where positive is from beginning of the month
and negative is from end of month
Outputs:
#theDate the date entered
#theNthDate the Nth date of the month
*/
Select theDate = #theDate
, dt.nthDate
From (Values (dateadd(month, datediff(month, #theNthDay, #theDate), 0))) As mm(FirstOfMonth)
Cross Apply (Values (dateadd(day, 7 * #theNthDay - 7 * sign(#theNthDay + 1)
+ (#theWeekday + 6 - datediff(day, -53690, mm.FirstOfMonth) % 7) % 7, mm.FirstOfMonth))) As dt(nthDate)
Where #theWeekday Between 1 And 7
And datediff(month, dt.nthDate, #theDate) = 0
And #theNthDay In (-5, -4, -3, -2, -1, 1, 2, 3, 4, 5);
Go
You can then call it like this:
Select * From dbo.fnGetNthWeekDay('2021-08-15', 6, -1) nwd

TSQL - SQL Server mumber of the week in Month

I am using the query below to get the number of the week in a month:
datepart(day, datediff(day, 0,TABLE.DATE), 102))/7 * 7)/7 + 1
Now I need to change the script that if a week ends in the next month, it should show 1 instead of 5.
Does anybody can help me?
Using Modulo by 4, you can get the month number 1 instead of 5.
For an example I tested with the 5th week and it result as 1:
DECLARE #TestDate AS DATETIME = '2016-07-29 10:00:00';
SELECT CASE ((DATEPART(DAY, DATEDIFF(DAY, 0, #TestDate)) /7 * 7) /7 + 1) % 4
WHEN 0 THEN 4
ELSE ((DATEPART(DAY, DATEDIFF(DAY, 0, #TestDate)) /7 * 7) /7 + 1) % 4 END
In your query, you wrongly used DATEPART. Actually it requires 2 parameters only.

T-SQL Dynamic date range in WHERE clause (Last fiscal year + year to date)

I'm using the following WHERE clause to only load records from the last fiscal year plus a year to date.
Running without the WHERE clause, it takes 30seconds for 1mil records. With the WHERE clause, I had to stop it after 2hours.
Can you please share your thoughts
WHERE
([schema].[table].[DATE] >= DATEADD
(yy, - 1, DATEADD
(MONTH,(MONTH(GETDATE()) - 1) / 6 * 12 - 6,
CAST(CAST(YEAR(GETDATE()) AS VARCHAR) AS DATETIME)
)
)
)
Declare #PastFiscalYear Date
Set #PastFiscalYear= DATEADD(yy, - 1, DATEADD(MONTH,(MONTH(GETDATE()) - 1) / 6 * 12 - 6,CAST(CAST(YEAR(GETDATE()) AS VARCHAR) AS DATETIME)))
WHERE
([schema].[table].[DATE] >= #PastFiscalYear )
Can you try this
This will bring back data since the previous fiscal year start date. Just change the -3 to what ever your FY offset is. -3 is for October.
[schema].[table].[DATE] >= DATEADD(mm,-3,DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, -1, GETDATE())), 0))

Convert iso_week to calendar date in SQL

I've been searching though the archives without finding what I am looking for- I'd be happy for some guidance.
I have a data set where I want to report aggregated number of appointments by provider (STAFFID) and work week, the latter defined by the week's Monday date. I've played with datepart(iso_week, appointment_date) as week_of_yr which gets me part of the way there- I can group by week to get the right numbers. However, I can't figure out if there's a simple way to display the date of the week's Monday given the iso_week integer (and year).
I found ISO8601 Convert Week Date to Calendar Date helpful, though I do not know whether (or how) I can automate that process for many values at once.
Here's the tidbit of code I have. Ideally I could add another expression to the select statement which would display the desired date.
select STAFFID
, count(*) as appointment_ct
, datepart(iso_week, appointment_date) as iso_wk --this returns the week # of the year as an int
from [dbo].[view_APPT_DATA]
where program_code in ('99999')
and appointment_date >= '1/1/2016' and appointment_date <='3/31/2016'
group by iso_wk, STAFFID
I would find the first Monday of that year and then use DATEADD to add the number of weeks to that day
select STAFFID
, count(*) as appointment_ct
, datepart(iso_week, appointment_date) as iso_wk --this returns the week # of the year as an int
, dateadd(week, datepart(week, DATEADD(DAY, (##DATEFIRST - DATEPART(WEEKDAY, dateadd(year, datepart(year, appointment_date) - 1900, 0)) + (8 - ##DATEFIRST) * 2) % 7, dateadd(year, datepart(year, appointment_date) - 1900, 0))) as monday_wk
from [dbo].[view_APPT_DATA]
where program_code in ('99999')
and appointment_date >= '1/1/2016' and appointment_date <='3/31/2016'
group by iso_wk, STAFFID, monday_wk
I didn't quite get the cha's query to return correct results for "special" years that have overlapping weeks.
This is the (inline) function i ended up with to calculate iso week to first day of that week:
CREATE OR ALTER FUNCTION dbo.FN_ISOWEEK_TO_DAY (
-- ISOWeek in format YYYYWW
#pISOWeek INT
)
RETURNS TABLE AS RETURN
SELECT DATEADD(week, CAST(RIGHT(#pISOWeek, 2) AS INT) - 1
- CASE WHEN (##DATEFIRST - DATEPART(WEEKDAY, DATEADD(YEAR, cast(LEFT(#pISOWeek, 4) AS INT) - 1900, 0)) + (8 - ##DATEFIRST) * 2) % 7 >= 4 -- means first monday is one week ahead
THEN 1 ELSE 0 END
, DATEADD(DAY, (##DATEFIRST - DATEPART(WEEKDAY, DATEADD(YEAR, cast(LEFT(#pISOWeek, 4) AS INT) - 1900, 0)) + (8 - ##DATEFIRST) * 2) % 7, DATEADD(YEAR, cast(LEFT(#pISOWeek, 4) AS INT) - 1900, 0)))
AS firstDay
Some test code:
SELECT *
FROM (
SELECT 202001, 20191230
UNION ALL
SELECT 202053, 20201228
) x (dt, expectedValue)
CROSS APPLY dbo.FN_ISOWEEK_TO_DAY(x.dt) y

SQL create a DateTime value from Year and Quarter

I know the year and the quarter (e.g. "2010" and "4") for a schedule-related milestone and I want to select/create a datetime from it. There are a number of nifty ways to identify the quarter with formats ("qq") of a particular date, but not to go the other way around (or are there?). This is with t-sql / SQL Server.
Note: the datetime should be for the last day of that quarter.
UPDATE: Here is the solution that I ended up using courtesy of gbn, with AaronLS's variable names and then shortened-and-sweetened with Frank Kalis' suggestion :-) It was important to test for all 4 quarters to make sure the year is handled properly. Thanks to everyone who answered!
DECLARE #TheQuarter INT
DECLARE #theYear INT
-- Note: qq = q = quarter for the datepart
SET #TheQuarter = 1
SET #TheYear = 2011
SELECT DATEADD(YEAR, #TheYear-1900, DATEADD(qq, #TheQuarter, -1))
-- 2011-03-31 00:00:00.000
SET #TheQuarter = 2
SET #TheYear = 2011
SELECT DATEADD(YEAR, #TheYear-1900, DATEADD(qq, #TheQuarter, -1))
-- 2011-06-30 00:00:00.000
SET #TheQuarter = 3
SET #TheYear = 2011
SELECT DATEADD(YEAR, #TheYear-1900, DATEADD(qq, #TheQuarter, -1))
-- 2011-09-30 00:00:00.000
SET #TheQuarter = 4
SET #TheYear = 2011
SELECT DATEADD(YEAR, #TheYear-1900, DATEADD(qq, #TheQuarter, -1))
-- 2011-12-31 00:00:00.000
Here are a few q's that fetch the quarter from the date but not the other way around:
Calculate the Last Day in the CURRENT quarter; Calculate the last day of the quarter; Best way to store quarter and year in SQL Server?
Never use strings for datetime conversions: too much to go wrong with formats, language etc.
Keep it in the datetime type...
Select dateadd(day, -1,
dateadd(year, #year-1900,
dateadd(quarter, #qq, 0)
)
)
Looks like you've already found your solution, but just for the sake of it...
If you choose a different base date, you can shorten the whole thing to
SELECT DATEADD(YEAR, #TheYear-1900, DATEADD(qq, #TheQuarter, -1))
Since 0 indicates SQL Server's base date of 01.01.1900 (and the first day of a month), using -1 as base date starts off 1 day earlier and then you already have your last day of a month (and end of a quarter). Then you just need to do the rest of the datetime magic and voilĂ .
Just choose the date from the quarter:
select
case #theQuarter
when 1 then '3/31/' + cast(#theYear as varchar(4))
when 2 then '6/30/' + cast(#theYear as varchar(4))
when 3 then '9/30/' + cast(#theYear as varchar(4))
when 4 then '12/31/' + cast(#theYear as varchar(4))
end as quarterDate
Edit: Adjusted to be last day of quarter instead of first day.
This basically gets the first day of the following quarter, and then subtracts one so that you have the last day of the quarter you wanted. (#theQuarter + 1) adds one to the quarter, then *3 -2 gets the first month of that quarter, and % 12 is required when for the fourth quarter because you add one to 4 to get 5, which gives you 13 but you really want 1, so the % takes care of that.
Finally after casting it all to a date time, we have the first day of the following quarter, thus subtract - 1 at the end to subtract one day and get the last day of the quarter we initially put in.
declare #theQuarter as int;
set #theQuarter = 4;
declare #theYear as int;
set #theYear = 2009;
select
cast(
cast(
( (#theQuarter + 1) * 3 - 2) % 12
as varchar(2))
+ '-01-'
+ cast( (#theYear + (((#theQuarter + 1) * 3 - 2)/ 12) ) as varchar(4))
as datetime) - 1 ;