How to find the 3rd business day of a month (Saturday and Sunday are weekend)? - sql

I need to find next final pay period under few conditions. The maturity is 3 months, but when the last payday is till the 3st business day of the current month. Оtherwise is the maturity 4 months. And Saturday and Sunday are not working days. For example: now in August 2019 are 3.08 and 4.08 not working day and when the customer pay the tax till 5.08(Monday - this is the 3st business day for a August) the next payday period is till end of Oktober 2019. Otherwise when the day is 6.08 is the period till end of November
IF #Schema = '1000'
BEGIN
SET #PayPeriod = 3
IF #Payday < DATEADD(DAY, CASE (DATEPART(WEEKDAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #Payday), 0)) + ##DATEFIRST) % 7
WHEN 6 THEN 2
WHEN 7 THEN 1 ELSE 0 END,
DATEADD(MONTH, DATEDIFF(MONTH, 0, Payday), 3))
SET #PayPeriod = EOMONTH(#Payday, #PayPeriod-1)
ELSE SET #PayPeriod = EOMONTH(#Payday, #PayPeriod)
END
And here is the result. After 06.08.2019 must be the payperiod end of November
2019-08-01 2019-10-31
2019-08-02 2019-10-31
2019-08-03 2019-10-31
2019-08-04 2019-11-30
2019-08-05 2019-11-30 here is the problem!
2019-08-06 2019-11-30

This should work for you:
declare #payday as datetime = '20190602'
;with cte as (
select datefromparts(year(#payday), month(#payday), 1) as monthday
union all
select dateadd(day, 1, monthday)
from cte
where day(monthday) < 10
)
select
case
when count(*) <= 3 then eomonth(#payday, 3)
else eomonth(#payday, 4)
end as MaturityEnd
from cte
where datepart(weekday, monthday) not in (7, 1)
and monthday <= #payday
Here we generate first couple of dates for the same month as in payment date and count business days smaller than payment date. Maturity end date is calculated based on the count of days.

It is not totally clear what you want from your question. I believe what you want is:
Give a date ##DATEFIRST find a date of maturity
3 months later unless
that date falls in the first 3 business days of a month than then
4 months later
Is that correct?
Also what does EOMONTH do? The use of it in your example does not seem to make sense compared to the stated requirements.

Related

Sum over defined Week limits

I have a rolling date with associated hours. I want to sum the hours over my defined 7-day week range of Saturday to Friday.
So I need to define any date as a week beginning Saturday, week ending Friday and sum over this range.
The table is in the form of:
Date
Day
Hours
2021-06-12
Saturday
3
2021-06-18
Friday
3
2021-06-21
Monday
1
2021-06-22
Tuesday
2
Grouping the above table into Saturday-Friday Week sums.
Saturday
Friday
Total_Hours
2021-06-12
2021-06-18
6
2021-06-19
2021-06-25
3
You can use date functions to get for each date (other than Saturday) the previous Saturday which is the start of the week it belongs too and group by that:
WITH cte AS (
SELECT *, DATEADD(day, -DATEPART(dw, Date) % 7, Date) Saturday
FROM tablename
)
SELECT Saturday,
DATEADD(day, 6, Saturday) Friday,
SUM(Hours) Total_Hours
FROM cte
GROUP BY Saturday
See the demo.
This code works in SQL Server but similar logic and functions can be used for other databases.
You don't have to tie this to datepart() or datename(), which in turn depends on DATEFIRST (alas!).
Instead, you can use date arithmetic. This in turn depends on the fact that 0 date is a Monday. But that is not configurable (as far as I know).
So:
select v.week as saturday, dateadd(day, 6, v.week) as friday,
sum(hours)
from t cross apply
(values (dateadd(day, 7*datediff(week, 0, dateadd(day, 1, t.date)) - 2, 0))
) v(week)
group by v.week
order by v.week;
Here is a db<>fiddle.

Get week period based on week number, month and year sql

I need to get the first day and the last day of the week based on the number of the week, year and month
My week starts on saturday and finish in friday
Example:
Year: 2020
Week: 45
Normal period of week: First day: 2020-10-31 ~ Last day: 2020-11-06
I need return something like
October: First day: 2020-10-31 ~ last day: 2020-10-31
November: First day 2020-11-01 ~ last day: 2020-11-06
my query to return last day of week:
select DATEADD (WEEK, #PcpSemana, DATEADD (YEAR, ('20' + LEFT(#PcpPeriodo,2))-1900, 0)) - 5 as lastDayOfWeek
my query to return first day of week
SELECT WeekStart = DATEADD(DAY,
(CEILING(DATEPART(DAY, DATEADD (WEEK, #PcpSemana, DATEADD (YEAR, ('20' + LEFT(#PcpPeriodo,2))-1900, 0)) - 5) / 7.0) - 1) * 7,
DATEADD(MONTH, DATEDIFF(MONTH, 0,DATEADD (WEEK, #PcpSemana, DATEADD (YEAR, ('20' + LEFT(#PcpPeriodo,2))-1900, 0)) - 5), 0));
I'm using SET DATEFIRST 6
I can't evolve much
PcpPeriodo contains YYMM ( 2011) = 2020 / 11 )
PcpSemana contains weeknumber (45) (01 ~ 53)
I am not sure what your data looks like, but if you have the first day of the week, you can split it among months as:
select weeks.*
from (values (convert(date, '2020-10-31'))) w(weekstart) cross apply
(values (dateadd(day, 6, w.weekstart), eomonth(w.weekstart))
) v(weekend, eom) cross apply
(values (w.weekstart,
case when v1.weekend <= v1.eom then v1.weekend else v1.eom end
),
(case when v1.weekend > v1.eom then dateadd(day, 1, v1.eom) end,
case when v1.weekend > 1.eom then v1.weekend
)
) weeks(weekstart, weekend)
where weeks.weekstart is not null;
This is using apply as a way of storing intermediate results, such as the last day of the month and when the week ends.
DECLARE #d datetime;
SET DATEFIRST 6;
SET #d = '2020-11-01';
WITH weektest as (
select #d as d
union all
select DATEADD(DAY,1,d) from weektest where d<='2020-11-6'
)
SELECT
d,
DATEPART(week, d),
DATEPART(weekday,d),
DATENAME(weekday,d)
from weektest;
output:
d
----------------------- ----------- ----------- ------------------------------
2020-11-01 00:00:00.000 45 2 Sunday
2020-11-02 00:00:00.000 45 3 Monday
2020-11-03 00:00:00.000 45 4 Tuesday
2020-11-04 00:00:00.000 45 5 Wednesday
2020-11-05 00:00:00.000 45 6 Thursday
2020-11-06 00:00:00.000 45 7 Friday
2020-11-07 00:00:00.000 46 1 Saturday

How to run different date ranges for different months in SQL

I have a requirement to automate dates for a report. The user runs the report four times a year.
Q1-jan-march- run may1
Q2-Apr-Jun - run Aug1
Q3-July-Sep - run Oct1
Q4-oct-dec - run feb1
when the user runs the query in May he should get the result for SELECT * FROM Table where DATE Between jan1 and march31. How do I write different date ranges according to the month it is being run.
Thanks In advance.
You seem to want to filter on the previous quarter. Here is one way to do it:
select *
from mytable
where date >= dateadd(qq, datediff(qq, 0, getdate()) - 1, 0)
and date < dateadd(qq, datediff(qq, 0, getdate()), 0)
This dynamically computes the beginning and end of the previous quarter based on the current date.
If the query subtracts 2 months from the current month, then the functions to determine the beginning and end of the quarter will always return the correct date range. Something like this
with example_run_dates as (
select cast(v.dt as date) dt
from (values ('20200501'), ('20200531'), ('20200801'), ('20200831'),
('20201001'), ('20201031'), ('20210201'), ('20210228')) v(dt))
select cast(dateadd(qq, datediff(qq, 0, mos.two_ago), 0) as date) start_dt,
cast(dateadd(qq, datediff(qq, 0, mos.two_ago)+1, -1) as date) end_dt
from example_run_dates erd
cross apply (select dateadd(month, -2, erd.dt) two_ago) mos;
Output
start_dt end_dt
2020-01-01 2020-03-31
2020-01-01 2020-03-31
2020-04-01 2020-06-30
2020-04-01 2020-06-30
2020-07-01 2020-09-30
2020-07-01 2020-09-30
2020-10-01 2020-12-31
2020-10-01 2020-12-31
DECLARE #FromDate NVARCHAR(255), #ToDate NVARCHAR(255)
SET #FromDate = CASE
WHEN MONTH(GETDATE()) = 5 THEN '20200101'
WHEN MONTH(GETDATE()) = 8 THEN '20200401'
WHEN MONTH(GETDATE()) = 10 THEN CONCAT(YEAR(GETDATE()),'0701')
WHEN MONTH(GETDATE()) = 2 THEN '20201001'
END
SET #ToDate = CASE
WHEN MONTH(GETDATE()) = 5 THEN '20200330'
WHEN MONTH(GETDATE()) = 8 THEN '20200630'
WHEN MONTH(GETDATE()) = 10 THEN CONCAT(YEAR(GETDATE()),'0930')
WHEN MONTH(GETDATE()) = 2 THEN '20201230' END
select #FromDate, #ToDate

SQL: First day of week Monday

I would like to display Monday as the first day of the week and Sunday the last day of the week.
I am using for this report the Report server.
my query:
Select
Datum,
Sum(Prod) as Prod
FROM (
Select
intervaldate as Datum,
Sum(case when TabName = 'Produzierte Dosen' then DisplayUnits else 0 end) as Prod
from vwOeeIntervalCount
where
IntervalDateWeek >= dateadd(wk, datediff(wk, 0, getdate()) - 1, 0)
and IntervalDateWeek < dateadd(wk, datediff(wk, 0, getdate()), 0)
and IntervalDate >= dateadd(day,datediff(day,0,GETDATE())-6,0)
AND IntervalDate < dateadd(day,datediff(day,0,GETDATE()),0)
and CalculationName = 'Packaging'
group by intervaldate
)c
group by Datum
Here the result:
Date |Prod
2018-02-25 00:00:00.000 |1836528
2018-02-26 00:00:00.000 |8131127,99999999
EDIT:
Sorry here is my question.
I would like to display the Monday as the first day of the week. My query displays the Sunday as the first day of the week.
How can I do that?
By default MS SQL Server has configured sunday as first day of a week.
You can set the server config for the first day of a week to any day with the following command:
SET DATEFIRST { number | #number_var }
Value First day of the week is
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
7 (default, U.S. English) Sunday
Source: https://learn.microsoft.com/en-us/sql/t-sql/statements/set-datefirst-transact-sql
you can use this to the current week:
/*-- Week Start
--1->Sunday --2->Monday....*/
SELECT CAST(DATEADD(dd, -(DATEPART(dw, GETDATE()))+2, GETDATE()) AS DATE) [WeekStart],
CAST(DATEADD(dd, 8-(DATEPART(dw, GETDATE())), GETDATE()) AS DATE) [WeekEnd]
/*-- Week End
--7->Saturday --8-> Sunday...*/
Running this today will produce this result:
WeekStart WeekEnd
---------- ----------
2018-02-26 2018-03-04
if you have dates in your table, you can use them instead of the GETDATE()

How to get month value using week value sql server

I want to get month value using week no.
I have week numbers stored in a table with year value.
How to query database to get month value using that week value.
I am using SQL
You can try this:
SELECT DATEPART(m,DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + CAST(t.year as VARCHAR(4))) + (t.week-1), 6))
It depends on how you're classing your week numbers, For example, if we assume that week numbers start on a Monday then we'd have to say that week 1 in 2016 actually started on Monday 28th of December 2015 and finished on Sunday 3rd January 2016. If this is how your week numbers are set up then you can use the method below
Sample Data;
CREATE TABLE #DateTable (WeekNum int, YearNum int)
INSERT INTO #DateTable (WeekNum, YearNum)
VALUES
(1,2016)
,(2,2016)
,(3,2016)
,(4,2016)
,(5,2016)
,(6,2016)
,(7,2016)
We will then cast the week and year into a date, then convert this to a month;
SELECT
WeekNum
,YearNum
,DATEADD(wk, DATEDIFF(wk, 7, '1/1/' + CONVERT(varchar(4),YearNum)) + (WeekNum-1), 7) AS WeekStart
,DATEPART(mm,DATEADD(wk, DATEDIFF(wk, 7, '1/1/' + CONVERT(varchar(4),YearNum)) + (WeekNum-1), 7)) MonthNum
(Edit: updated as source is int)
Gives these results;
WeekNum YearNum WeekStart MonthNum
1 2016 2015-12-28 00:00:00.000 12
2 2016 2016-01-04 00:00:00.000 1
3 2016 2016-01-11 00:00:00.000 1
4 2016 2016-01-18 00:00:00.000 1
5 2016 2016-01-25 00:00:00.000 1
6 2016 2016-02-01 00:00:00.000 2
7 2016 2016-02-08 00:00:00.000 2
You can't go from week number to month because weeks can occur in two different months. For example the 31st Jan 2016 and 1st Feb 2016 are both in week 6.
SELECT DATEPART(WEEK, '2016-01-31')
SELECT DATEPART(WEEK, '2016-02-01')
You can try the query below:
SELECT
[Week],
[Year],
'Output-Month' = MONTH(DATEADD(WEEK, [Week], DATEADD(WEEK, DATEDIFF(WEEK, '19050101', '01/01/' + CAST([Year] AS VARCHAR(4))), '19050101')))
FROM YourTable
1st is to get the 1st day of the year using this:
DATEADD(WEEK, DATEDIFF(WEEK, '19050101', '01/01/' + CAST([Year] AS VARCHAR(4))), '19050101')
2nd is to add your number of week using this:
DATEADD(WEEK, [Week], 'From 1st result')
Last is getting the number of Month using the MONTH function.