Calculating Billing Weeks based on billing week date - sql

Given the following dates:
Start Date: 09/17/2015
End Date 04/01/2016
I am attempting to calculate the total number of weeks and the billing weeks per month, billing weeks to date, and forecasted billing weeks.
Since our billing is only done by week to avoid prorating, this is a little difficult.
I.e,
The total number of weeks would be 29 using the following:
(select ceiling(convert(float,DATEDIFF(day,'09/17/2015','04/01/2016')+1)/7))
More over if I were to run this report on 8th of Jan 2016,
It should give me 1 week as the billing weeks billed to date, with the remaining 4 weeks as a forecast.
I was thinking of creating a couple of fields:
WeekStart and WeekEnd as dates fields, Month and Year field. And then to filter by dates where end date < today's date. Then aggregate that by the current month.
Example:
Weekstart: 09/17/2015
Weekend: 09/23/2015
Month: September
Year: 2015
Weekstart: 09/24/2015
Weekend: 09/30/2015
Month: September
Year: 2015
......
......
......
Weekstart: 03/31/2016
Weekend: 04/06/2016
Year: 2016
Month: March
Does this sound logical?
How can I go about creating this stored procedure. Any starting point would be very helpful.
Here is the quick sample Stored Proc I have created:
Here is the following sample I created, this should would I believe:
DECLARE #startdate datetime = '09/17/2015'
DECLARE #enddate datetime = '04/01/2016'
WHILE (#startdate <= #enddate)
BEGIN
Print CONVERT(VARCHAR, #startdate, 120) + '-----'+ CONVERT(VARCHAR, DateAdd(DD,+6,#startdate), 120)
set #startdate = DateAdd(DD,+6,#startdate)+1 ;
END

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.

Converting dates to periods - last saturday of each month 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.

Date Diff - Parse Today's Date to capture the end of the fiscal year

Trying to come up with a way to use today's date to return a value I can use in a DateDiff function.
DateDiff (Month, Sales_Date, the end of our fiscal year using today's date)
Our fiscal year starts 4/1 and goes through 3/31
Any date (from getdate()) on or before 3/31 I would use the '3/31/' + the value of the getdate's year.
Any date (from getdate()) on or after 4/1 I would use '3/31/' + the value of the getdate's year + 1.
The end result will give me the number of months from the date of the original sale date to the end of the current fiscal year
Example
Today's date is 6/18/20, so the last parameter in the above DateDif formula would be 3/31/2021
I will be using the column in the below code:
Select g.sales_month,g.fiscal_year as FY, g.Sales_Type,v.region, sum(g.FY_Total) as FY_Total
from sales_FY g JOIN dbo.dimsummary AS v ON g.sales_id = v.sales_id
group by g.sales_Month, g.fiscal_year, v.Region, g.Sales_Type
Example:
Picture of the end result using Excel format
Subtract 3 months and extract the month. That gives you the month of this month in the fiscal year. Then subtract this value from 11 or 12 (I'm not exactly sure which is better for "number of months left"):
select 11 - month(dateadd(month, -3, getdate())

How to change day of date in SQL server and set last day of month if the day does not exist in the month

I tried using this
dateadd(month, 0, dateadd(day,(30-datepart(dd,'2015-02-28')),'2015-02-28'))
to get the required output and instead of getting '2015-02-28' i get '2015-03-02'. How is it possible to change day of date in SQL and set last day of month if the day does not exist in the month ?
====Update with sample data =============
Note: Goal is not to get the last day of the month
If i want to change the day to 30 and if it's a month which has only 28 days. it should be the end of the month date. If not date should be 30th.
Changing the day to 30th
If Feb it should be - '2015-02-28'
If march it should be - '2015-03-30'
If April it should be - '2015-04-30'
There exists a function for this if your sql server version is 2012 or higher:
SELECT EOMONTH('2015-02-15')
returns 2015-02-28
-- Replace Day portion of #OrigDate with #NewDay.
-- If the result would be beyond the end of the month, return the last day of the month
create function ReplaceDay ( #OrigDate date, #NewDay int )
returns date
as
begin
declare #NewDate date
-- Deal with extreme cases, in case someone passes #NewDay = 7777 or #NewDay = -7777
if #NewDay < 1
set #NewDay = 1
if #NewDay > 31
set #NewDay = 31
-- Subtract the DAY part of the original date from the new day.
-- Add that many days to the original date
-- Example: if the original date is 2018-02-08 and you want to replace 08 with 17, then add 17-08=9 days
set #NewDate = DateAdd ( d, #NewDay-Day(#OrigDate), #OrigDate )
-- Have we ended up in the next month?
-- If so subtract days so that we end up back in the original month.
-- The number of days to subtract is just the Day portion of the new date.
-- Example, if the result is 2018-03-02, then subtract 2 days
if Month(#NewDate)<>Month(#OrigDate)
set #NewDate = DateAdd ( d, -Day(#NewDate), #NewDate )
return #NewDate
end
go
select dbo.ReplaceDay ( '2017-02-08', 17 ) -- Returns 2017-02-17
select dbo.ReplaceDay ( '2017-02-08', 30 ) -- Returns 2017-02-28
for sql server 2012 or higher versions please check HoneyBadger's answer.
for older versions:
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#mydate)+1,0))

SQL Server Date Logic - Finding the next reminder date

Given the following database table:
StartDate DATETIME -- day that the reminder period starts
LastReminderDate DATETIME -- the last time the reminder triggered
DayOfMonth INT -- the day of the month to remind the user
Interval INT -- how often in months to remind the user
How can I figure out the next reminder date based on these values? For example:
StartDate = '6/1/2011'
LastReminderDate = '6/5/2011'
DayOfMonth = 5 -- remind on the 5th of the month
Interval = 2 -- remind every other month
For this particular example, the next reminder date should be 8/5/2011 because it reminds on the 5th of the month every two months. How would I write a function to figure this out?
If LastReminderDate is NULL, then LastReminderDate should be equal to StartDate
UPDATE:
StartDate = '6/1/2011'
LastReminderDate = NULL
DayOfMonth = 5
Interval = 2
In this case, there was no last reminder date. The first time the reminder would occur would be 6/5/2011. The solutions below seem to be returning 8/5 in this case.
Here are some specific rules:
The Reminder should always occur on whatever DayOfMonth is. If DayOfMonth would be illegal for the given month then it should be the last day of that month. For example....if DayOfMonth is 31 and the next reminder date would fall on June 31, then it should be June 30th instead.
The next reminder date should always be based off of the Last Reminder Date plus the Interval. If Last Reminder Date does not match the Day of Month, then it could potentially be more than what the interval was. For example...if Last Reminder was 6/1/2011 and the interval is 2 months, but the reminder is for the 20th of the month, then the next reminder will be 8/20/2011.
If there is no last reminder date, then use the Start Date instead of last reminder date...but this will use the earliest date in the future. If start date was 6/1/2011 and day of month is 5, then this will be 7/5/2011 since today is 6/22/2011. If Day of Month was 25 then it would be 6/25/2011
DECLARE
#StartDate AS datetime, -- day that the reminder period starts
#LastReminderDate AS datetime, -- the last time the reminder triggered
#DayOfMonth AS integer, -- the day of the month to remind the user
#Interval AS integer -- how often in months to remind the user
SET #StartDate = '6/1/2011'
SET #LastReminderDate = '6/5/2011'
SET #DayOfMonth = 5 -- remind on the 5th of the month
SET #Interval = 2 -- remind every other month
SELECT
CASE
WHEN #LastReminderDate IS NULL
THEN
CASE WHEN Day(#StartDate) <= #DayOfMonth
THEN DateAdd( month, ((Year( #StartDate ) - 1900) * 12) + Month( #StartDate ) - 1, #DayOfMonth - 1 )
ELSE DateAdd( month, ((Year( #StartDate ) - 1900) * 12) + Month( #StartDate ) - 0, #DayOfMonth - 1 )
END
ELSE DateAdd( month, #Interval, #LastReminderDate )
END
The meat of this is the last four lines, the SELECT CASE ... END statement. I provided a whole script that lets you plug in different values, and see how the SELECT CASE ... END behaves for those test values.
But to just use this on your table, use only the last four lines (and remove the # from the front of the names so they match the table's column names).
You could also generalize this so that Interval doesn't have to be months. If your table had an IntervalType column, you could supply that as the first argument to DateAdd(). See the docs but some common intervals are days, months, years, and so on.
EDIT2: Respect DayOfMonth.
Since you want to use the StartDate if there is no LastReminderDate, then you'll want to use COALESCE for that bit of logic: COALESCE(LastReminderDate, StartDate)
Now, get to the last of the previous month: DATEADD(DAY, -DAY(COALESCE(LastReminderDate, StartDate)), COALESCE(LastReminderDate, StartDate))
Finally, add the months and then get to the date that we need:
DATEADD(MONTH, Interval, DATEADD(DAY, -DAY(COALESCE(LastReminderDate, StartDate)) + DayOfMonth, COALESCE(LastReminderDate, StartDate)))
This will potentially go forward less than two months if the date of the last reminder was on a day of the month after the "DayOfMonth" that's configured for the reminder. You should be able to tweak that depending on what your business logic is in that situation.