Converting dates to periods - last saturday of each month sql - sql

Not a strong SQL user by any means. I'm trying to run a script that will return the fiscal period given the date of the transaction. The fiscal period is up to the last saturday of each month.
So for the year 2022, period 1 January would be Jan 1, 2022 to Jan 29,2022 (last saturday) and Feb would be Jan 30th to Feb 26, 2022 (last saturday). I need to run this script for multiple years.

Give this a go, is it for MSSQL but would be pretty easy to flip around for many other DBMS. Just that each is a little tricky with their own date/time syntax. That being said the general concept should work for just about any of them as I'm not using anything unique to MSSQL.
DECLARE #DATE datetime
DECLARE #EOM datetime
DECLARE #SAT datetime
-- set a date to use
SET #DATE = '2022-06-28'
-- add a month
SET #EOM = DATEADD(mm, 1, #DATE)
-- subtract the days to get last day of month
SET #EOM = DATEADD(dd, -DAY(#EOM), #EOM)
-- subtract days using weekday number to get Saturday
SET #SAT = DATEADD(dd, -(DATEPART(dw, #EOM))-1, #EOM)
-- display the result
SELECT #EOM as [EOM]
, DATENAME(dw, #EOM) as [EOM_Day]
, #SAT as [Last_Sat]
, DATENAME(dw, #SAT) as [Last_day]
Although in my experience I would use this to create a calendar table of sorts. It can be hard to use a function like this to JOIN to, etc. But if you have the dates and results all stored out for the next 10 (or more) years it makes it much easier to use.

Related

WTD this year compared to WTD last year

I would like to determine the growth on sales data from current year WTD with sales data from the same week last year also WTD.
So if this week is Mon, Tue, Wed I am trying to compare Mon, Tue, wed from the same week last year to determine the sales growth. This needs to be dynamic in a sense since it will be running on a daily report, ending WTD on the previous day, through SSRS which will be emailed to various users.
I have done copious amounts of online searching and tried several iterations, all with undesirable affects.
The latest attempt being
SELECT
[storeid],
SUM([Sales]) as [2021SalesWTD]
FROM [dbo].[DailySales2021]
WHERE CONVERT(date, [date]) >= DATEADD(DAY, 1-DATEPART(dw, DATEADD(YEAR,-1,GETDATE())), CONVERT(date, DATEADD(YEAR,-1,GETDATE())))
AND DATEADD(DAY, 8-DATEPART(dw, DATEADD(YEAR,-1,GETDATE())), CONVERT(date, DATEADD(YEAR,-1,GETDATE())))
GROUP BY storeid
This returns the entire week
It might help you to try variable declarations.
Here's something I've drafted up:
--Get today's date, find the day of the week (1 indexed from Sunday) and subtract. Add 2 to balance this offset
DECLARE #MondayThisYear AS DATE = CAST(GETDATE()-DATEPART(WEEKDAY, GETDATE())+2 AS DATE)
--Get the date a year ago. I haven't checked for leap year, add it if you need it
DECLARE #DateLastYear AS DATE = #MondayThisYear-365
--Same idea as MondayThisYear, but using the date from last year
DECLARE #MondayLastYear AS DATE = CAST(#DateLastYear-DATEPART(WEEKDAY, #DateLastYear)+2 AS DATE)
--The number of days that have passed in this working week
DECLARE #WorkingDays AS INT = DATEDIFF(d, #MondayThisYear, GETDATE())
SELECT [insert columns]
FROM [insert table name]
WHERE ([date column]>#MondayThisYear AND [date column]<GETDATE()) OR
([date column]>#MondayLastYear AND [date column]<#MondayLastYear + #WorkingDays)
You might also need to check how I've defined the previous year's dates. In worst case you might get an off-by-one week error, but I don't think that's avoidable given the structure of the calendar.

SQL query that displays the current date and count of days between two specific dates

I am trying to write a SQL query that shows the count of the days and date depending upon the financial period it falls in. The financial period starts 5 days before the month end eg march 27th to 26th April
For the above mentioned period if the day is 29th march, the count of the day should be 3 and the date should be 2020-04. The date should adjust depending upon the period it falls in.
I tried to adress the second part of this query by writing the below script but it does not bring any result
declare #date datetime
set #date = getdate()
SELECT format (date,'yyyy-MM-dd') as date
where #date
between dateadd(day,-5,EOMONTH(getdate(),-1)) and dateadd(day,-5,EOMONTH(getdate()))
updated to include 5 days from previous month.
Is this what you are looking for the second part?
Edit: Modifying the query. I guess this should give you what you need for both the parts.
you can try changing the dates in set #date.
Please note that the -4 instead of -5 is done intentionally as you said the financial month starts 5 days earlier. For March, 31 - 5 would give 26, but it should start on 27 right? so that on 29th the no. of days should be 3 including 27 and 29. Anyways, the query should be self explanatory, might just need to change the number depending on your requirement.
declare #date datetime
--set #date = getdate()
set #date = '2020-02-14'
SELECT format(#date,'yyyy-MM-dd') as date,
case WHEN #date < dateadd(day,-4,EOMONTH(#date)) THEN format(EOMONTH(#date),'yyyy-MM')
ELSE format(EOMONTH(#date, 1),'yyyy-MM') END
AS FinancialMonth,
CASE WHEN #date < dateadd(day,-4,EOMONTH(#date)) THEN DATEDIFF(day,dateadd(day,-5,EOMONTH(#date,-1)), #date)
ELSE DATEDIFF(day, dateadd(day,-5,EOMONTH(#date)), #date) END
AS CountDays
The following code will calculate what you need. Please read the comments in the code itself.
-- First, lets declare all the variables we need.
-- I tried to name them so they are selfexplanatory.
declare #inputdate DateTime,
#financialPeriodStartDate DateTime,
#EndOfTheMonth DateTime,
#nextFinantialMonthYear DateTime,
#previousFinancialPeriodStartDate DateTime
-- Now we calculate some of the values
set #inputdate = GETDATE() -- Let's use Today's date, but you can change this to any date.
set #EndOfTheMonth = EOMONTH(#inputdate) -- This is the end of the month for the input date
set #financialPeriodStartDate = DATEADD(DAY,-5,EOMONTH(#inputdate)) -- This is you Financial Period Start Date for the giving input date.
set #previousFinancialPeriodStartDate = DATEADD(DAY,-5,EOMONTH(DATEADD(MONTH, -1, #inputdate))) -- Also calculates the Start Date of the precious financial period.
set #nextFinantialMonthYear = DATEADD(MONTH, 1,#financialPeriodStartDate) -- This is the start date of the next financial period.
-- In the following Select, it calculates the values you need, based in the previous variables.
select
#inputdate as Today,
#EndOfTheMonth as EndOfMonth,
#previousFinancialPeriodStartDate as PreviousFinancialPeriodStartDate,
#financialPeriodStartDate as FinacialPeriodStartDate,
CASE WHEN DATEDIFF(DAY , #financialPeriodStartDate, #inputdate + 1 ) < 0
THEN DATEDIFF(DAY , #previousFinancialPeriodStartDate, #inputdate + 1 )
WHEN DATEDIFF(DAY , #financialPeriodStartDate, #inputdate + 1 ) >=0
THEN DATEDIFF(DAY , #financialPeriodStartDate, #inputdate + 1 )
END as DaysFromFPStartDate,
STR(YEAR(#nextFinantialMonthYear)) +'-'+LTRIM(RTRIM(STR(MONTH(#nextFinantialMonthYear)))) as NextFinantialPeriodMonthAndYear
I hope it helps.

SQL 'Round' Up a Date to a Given Day of the week

My company groups all tasks into individual weeks that end on a Thursday. Thus a task due on 3/20/19 would be grouped into the 3/21 week and tasks due on 3/22 group into the 3/28/19 week.
I'm looking to calculate this field (called duedate_Weekdue) based on an input duedate.
The following works but doesn't seem like the simplest way to do this. Anyone have more elegant methods?
Select
getdate() as duedate,
datepart(yy,getdate()) as duedate_yr,
datepart(ww,getdate()) as duedate_ww,
CASE
When datename(dw,Dateadd(day,1,getdate()))='Thursday' Then Dateadd(day,1,getdate())
When datename(dw,Dateadd(day,2,getdate()))='Thursday' Then Dateadd(day,2,getdate())
When datename(dw,Dateadd(day,3,getdate()))='Thursday' Then Dateadd(day,3,getdate())
When datename(dw,Dateadd(day,4,getdate()))='Thursday' Then Dateadd(day,4,getdate())
When datename(dw,Dateadd(day,5,getdate()))='Thursday' Then Dateadd(day,5,getdate())
When datename(dw,Dateadd(day,6,getdate()))='Thursday' Then Dateadd(day,6,getdate())
When datename(dw,Dateadd(day,0,getdate()))='Thursday' Then Dateadd(day,0,getdate())
END as duedate_Weekdue;
You can reduce that to one line of code that uses a little math, and some SQL Engine trivia.
The answers that depend on DATEPART return non-deterministic results, depending on the setting for DATEFIRST, which tells the SQL Engine what day of the week to treat as the first day of the week.
There's a way to do what you want without the risk of getting the wrong result based on a change to the DATEFIRST setting.
Inside SQL Server, day number 0 is January 1, 1900, which happens to have been a Monday. We've all used this little trick to strip the time off of GETDATE() by calculating the number of days since day 0 then adding that number to day 0 to get today's date at midnight:
SELECT DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()),0)
Similarly, day number 3 was January 4, 1900. That's relevant because that day was a Thursday. Applying a little math to the number of days, and relying on the DATEDIFF function to drop fractions, which it does, this calculation will always return the next Thursday for you:
SELECT DATEADD(DAY, (DATEDIFF(DAY, 3, GETDATE())/7)*7 + 7,3);
Credit to this answer for the assist.
So your final query comes down to this:
Select
getdate() as duedate,
datepart(yy,getdate()) as duedate_yr,
datepart(ww,getdate()) as duedate_ww,
DATEADD(DAY, (DATEDIFF(DAY, 3, GETDATE())/7)*7 + 7,3) as duedate_Weekdue;
If the first day of the week is Sunday, by using the modulo operator %:
cast(dateadd(day, (13 - datepart(dw, getdate())) % 7, getdate()) as date) as duedate_Weekdue
I also applied the casting of the result to date.
Try identifying number of day in week with DATEPART and then adding enough days to go to next thursday:
declare #dt date = '2019-03-22'
declare #weekDay int
SELECT #weekDay = DATEPART(dw, #dt)
if #weekDay <= 5
select DATEADD(day, 5 - #weekDay ,#dt)
else
select DATEADD(day, 12 - #weekDay ,#dt)

Two Predefined Dates

If I want to search records based on the previous month's stats how would I do that? So, if I want a report on June 15th, it would include May 15-June 14. A report for July 15th would include June 15-July 14 and so on. As of now I have this:
where currentemploydate between CAST('2013/05/15' AS DATETIME) AND CAST('2013/06/14' AS DATETIME)
but then I don't know how to auto update the dates for next month. If the report is ran on the 20th, it still shows the dates from the 14th of the current month back to the 15th of the previous month
Then I think you want:
where currentemploydate between CAST('2013-05-15' AS DATETIME) AND
dateadd(month, 1, CAST('2013-05-15' AS DATETIME) )
This should work for any date constant.
DECLARE #START datetime
SET #START = '2012-07-31'
DECLARE #END datetime
SET #END = DATEADD(DAY, 30, #START)
select #START, #END
Assuming a month is 30 days though....is that an acceptable assumption?

Write SQL Code to automate the changing of the parameter year and period

If the day of the current date = 14 then the values of the parameter need to change.
The month and possibly year will need to advance by 1
- May need to consider that on the 14th day of the month there may be a technical problem that prevents this process from running.
Example Friday is the 14th when the sql script is run on the sql server and sees that its the 14th then the field prmstring needs to be updated from 201305 to 201306.
SET #start = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()-13), 0)
SET #stop = DATEADD(MONTH, 1, #start)
The -13 moves everything back 13 days.
- The 1st to 13th of each month, are moved to a date in the previous month
- The 14th onwards of each month, stay in the same month
The DATEADD(DATEDIFF()) rounds the date down to the beginning of the month.
In this way the 1st to 13th of every month are rounded down to the 1st of the previous month. And the 14th onwards are rounded down to the 1st of the current month.
The end date is then simply the value calculated above, plus 1 month.
How about this?
select
substring(
convert(
varchar(10),
dateadd(mm, 1, dateadd(mm, datediff(mm, 0, dateadd(d,-13,getdate())), 0))
,112)
,1,6) as newDate
this is what worked
DECLARE #curentday VARCHAR(2)
select #curentday =datepart(day,getdate())
declare #yearmonth varchar (6)
select #yearmonth =convert(varchar,getdate(),112)
If #curentday in (14,15,16)
begin
if (select prmString11 from FC_App where prmName1='prmCurFCPrd') <> #yearmonth
begin
update FC_App
set prmString11 = #yearmonth
where prmName1='prmCurFCPrd'
update FC_App
set prmString11 = CONVERT(VARCHAR(6),DATEADD(dd,1-day((DATEADD(mm,-1,GETDATE()))),DATEADD(mm,- 1,GETDATE())),112)
where prmName1='prmcurWIPPrd'
End
end