all, I need help about my works
I have to compare data between current month and previous month and also with date and day range. I have amount in current month (December) between 1st December and 3rd December. 1st December is on Wednesday, 2nd December is on Thursday, and 3rd December is on Friday. 1st December until 3rd December is the first week on December. The previous month, first week on November, Wednesday until Friday is on 3rd, 4th and 5th November.
How can I perform this in SQL Server?
What I've tried is looked like this:
select *
from (
-- Current Month
SELECT Businessday, Amount, datename(dw,BusinessDay) AS DaysName,
DATEDIFF(WEEK, DATEADD(MONTH, DATEDIFF(MONTH, 0, BusinessDay), 0), BusinessDay) +1 AS WeekNumber
FROM TableTransaction
WHERE Businessday BETWEEN '2021-12-01 00:00:00.000' AND '2021-12-03 00:00:00.000'
) x left join (
-- Previous Month
SELECT Businessday, Amount, datename(dw,BusinessDay) AS DaysName,
DATEDIFF(WEEK, DATEADD(MONTH, DATEDIFF(MONTH, 0, BusinessDay), 0), BusinessDay) +1 AS WeekNumber
FROM TableTransaction
WHERE Businessday BETWEEN '2021-11-01 00:00:00.000' AND '2021-11-30 00:00:00.000'
) y on x.DaysName = y.DaysName AND x.WeekNumber = y.WeekNumber
Another thought is, How if range date which I chose is 23th December until 30th December which is Thursday in fourth week, the previous month is (Thursday in fourth week) the range is until first week of December, how can I perform this?
Your answer will be so helpful.
Related
I am writing a SQL query to find business working dates of last year equivalent to today's date.
In this query it should fetch :-
For e.g. if today is 5th January, 2021 and it is the second day of second week of the year. So I need to find the exact equivalent date of the second day of second week of the previous year. So it would be 7th January, 2020.
And with this, I need the business working dates of that week of 7th January 2020 (i.e. excluding Saturday & Sunday)
Which will come up as 2020-Jan-06 to 2020-Jan-10 according to the example.
So I will need the report between 6th Jan - 10th Jan, 2020.
I am trying to use this code to find date of last year equivalent to today's date (5th Jan, 2021 viz. second day of second week)
select Convert(date, (DATEADD(year, -1, getdate()+2))) ;
2021-01-05 is the 2nd day of the first week of 2021 according to ISO standards.
If you want the 2nd day of the first week of 2021, then it is either today's date minus 52 weeks or 53 weeks. Based on the Wikipedia page for ISO dates:
[53 week years are those] years in which 1 January or 31 December are Thursdays
So, we want that for the previous year. Hence, I think the following should work:
select dateadd(week,
(case when 'Thursday' in (datename(weekday, datefromparts(year(getdate()) - 1, 1, 1)),
datename(weekday, datefromparts(year(getdate()) - 1, 12, 31))
)
then -53 else -52
end),
convert(date, getdate())
)
Note that this returns 2019-12-31, which is the correct value based on ISO standards.
I have use multiple CTE to show you the step by step calculation. It should be pretty easy to follow.
Basically it find the week_no and day_no_of_week for 2021-01-05 and then use that to find the same date for 2020
declare #input_date date = '2021-01-05',
#year_offset int = -1; -- previous year
with
cte1 as
(
select input_date = #input_date,
week_no = DATEPART(WEEK, #input_date),
first_day_of_week = DATEADD(WEEK, DATEDIFF(WEEK, 0, #input_date), 0)
),
cte2 as
(
select *,
day_no_of_week = DATEDIFF(DAY, first_day_of_week, #input_date) + 1
from cte1
),
cte3 as
(
select *,
first_day_of_the_prev_year = DATEADD(YEAR, DATEDIFF(YEAR, 0, #input_date) + #year_offset, 0)
from cte2
),
cte4 as
(
select *,
first_day_of_week_prev_year = DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(WEEK, week_no - 1, first_day_of_the_prev_year)), 0)
from cte3
)
select *,
DATEADD(DAY, day_no_of_week - 1, first_day_of_week_prev_year) as the_required_date
from cte4
I would need to find month's week number. I know the ways to find week number for year but not a month's.
Example:
Sep 2019
Week 1 – 1st to 1st
Week 2 – 2nd to 8th
Week 3 – 9th to 15th
Week 4 – 16th to 22nd
Week 5 – 23rd to 29th
Week 6 – 30th to 30th
I tried finding one using below logic but it's taking 1st of Sep 2019 as 4th week. But I need the value as 1 here
declare #date datetime = '2019-09-01'
select datepart(day, datediff(day, 0, #date)/7*7)/7, datepart(day, datediff(day, 0, #date)/7 * 7)/7 + 1
Appreciate your help with this.
Try with this
DECLARE #MyDate DATETIME
SET #MyDate = '2019-09-01'
SELECT DATEPART(WEEK, #MyDate) - DATEPART(WEEK, DATEADD(MM, DATEDIFF(MM,0,#MyDate), 0))+ 1 AS NoOfWeeks
For the below query
Sum(CASE WHEN dbo.sales.date BETWEEN '2016-07-17' AND '2016-07-23' THEN dbo.sales.sellinc END) AS ActualSales
Instead of hard coding the date. I would like to pick current date from machine and compare
Sum(CASE WHEN dbo.sales.date BETWEEN '**previous week (31 week 2016)**' AND '**Last year same week (31 week 2015)**' THEN dbo.sales.sellinc END) AS ActualSales
Week start from Sunday and ends Saturday. Any help please?
I think this snippet might help you to get a range of one year from the previous week to last year.
Sum(CASE
WHEN dbo.sales.date
BETWEEN DATEADD(YEAR, -1, DATEADD(WEEK, -1, GETDATE())) AND
DATEADD(WEEK, -1, GETDATE()) THEN dbo.sales.sellinc END) AS ActualSales
You can also modify the logic if you want to consider Friday as an exception.
In that case, you have to use DATEPART(WEEKDAY, GETDATE()) function to get the week day which returns 1 for Sunday and 7 for Saturday. It would be prettier if you move the date generation logic to a variable and then use it to select your data.
Others have already noted that your method of week numbering is going to impact your solution. Here's one that just looks for the Sunday of the current week and then subtracts 52 weeks. (You could also just deduct 364 days in the previous step and use dateadd only once.) So the correspondence with the previous year's week is essentially the nearest calendar date falling on Sunday that year.
with dates as (
select
dateadd(week, -52,
dateadd(day,
1 - datepart(weekday, getdate()), /* Sunday of current week */
cast(getdate() as date)
)
) as WeekStartY-1,
dateadd(day, 1 - datepart(weekday, cast(getdate() as date)) as WeekStartY-0
)
select
sum(case when cast(s."date" as date)
between d.WeekStartY-0 and dateadd(day, 6, WeekStartY-0) then s.sellinc end
) as ActualSalesY-0,
sum(case when cast(s."date" as date)
between d.WeekStartY-1 and dateadd(day, 6, WeekStartY-1) then s.sellinc end
) as ActualSalesY-1,
from dbo.Sales s cross apply dates d;
This can occasionally produce an oddity where the weeks both start in the same year. It happens when the year ends on Sunday, or Monday in leap years, as with 2012. So Y-1 for December 30, 2012 was January 1, 2012. But consider that most of the days for that week actually fall in 2013 and the correspondence makes sense from that perspective.
You can try using DATEADD:
SUM(CASE WHEN dbo.sales.date BETWEEN DATEADD(week, 30, '2016/01/01') AND
DATEADD(week, 30, '2015/01/01')
THEN dbo.sales.sellinc END) AS ActualSales
This will give you the one year range between the 30th week of 2015 and 2016, using the SQL Server week, whose first week begins on January 1st, regardless of the day. If you really want to use the ISO week, then it will be a lot more work.
How the calculation happen for MONTH datepart in DATEADD()
Add Month
SELECT '2012-01-29' AS [Date], CAST(DATEADD(MONTH, 1, '2012-01-31') AS DATE) AS NextDate
UNION
SELECT '2012-01-31' AS [Date], CAST(DATEADD(MONTH, 1, '2012-01-31') AS DATE) AS NextDate
UNION
SELECT '2013-01-31' AS [Date], CAST(DATEADD(MONTH, 1, '2013-01-31') AS DATE) AS NextDate
Result
Subtract Month
SELECT '2012-02-29' AS [Date], CAST(DATEADD(MONTH, -1, '2012-02-29') AS DATE) AS PrevDate
UNION
SELECT '2012-03-01' AS [Date], CAST(DATEADD(MONTH, -1, '2012-03-01') AS DATE) AS PrevDate
Result
When I add a Month for the dates 29,30,31 of Jan'2012, I get the same result as February 29. For subtract, for the date 29 Feb'2012, it shows 29 Jan'2012. There is no way to get the dates 30 & 31 of Jan'2012.
I want to know some brief explanation.
The behaviour is explicitly documented in the documentation for DATEADD:
DATEADD (datepart , number , date )
...
If datepart is month and the date month has more days than the return month and the date day does not exist in the return month, the last day of the return month is returned. For example, September has 30 days; therefore, the two following statements return 2006-09-30 00:00:00.000:
SELECT DATEADD(month, 1, '2006-08-30');
SELECT DATEADD(month, 1, '2006-08-31');
As to why it has this behaviour, it all comes down to the fact that variable length months mean that you have to apply some form of tradeoff when performing date maths, and no one "correct" answer exists. Do you think of 31st January as being "the last day of January" or "30 days after the 1st day of January". Both of those are correct ways of thinking about the 31st. But if you change January to February, you now obtain two different dates - 28th or 29th of February for "the last day of February" or 2nd or 3rd of March for "30 days after the 1st day of February".
But functions have to return just one value.
I'm not saying that SQL Server applies either of the above interpretations. What it does do, though, is ensures that if you add, say, 1 month onto a particular date, you can be sure that the resulting date falls in the following month.
Reverse question is -
How to determine if the date is in last week of month?
For example, using GetDate() how would I know that today's date or given date is in last week of the month.
As week number in MSSQL can be 4 or 5.
Suppose I want to get date of last Saturday of every month.
But in SQL week number 5 (which is last week of Dec 2013) for Dec 2013 don't have Friday. Last week of December ends with Tue on 31st.
So, I need to skip Dec and go further for January 2014 but there also last week ends on Friday 31st.
So, keep moving....
So, how to get date of last week's X day from given date or today's date?
Thanks.
You can use the code below. It is based on week starting on Monday and ending on Sunday:
declare #date as date = '20131230' -- this is the date you check
declare #lastdayofmonth as date = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#date)+1,0))
declare #lastweekstart as date = dateadd(d, -datepart(dw, #lastdayofmonth)+2, #lastdayofmonth)
if datepart(m, #lastdayofmonth) <> datepart(m, #lastweekstart)
set #lastweekstart = dateadd(d, -7, #lastweekstart)
if #date >= #lastweekstart and #date <= #lastdayofmonth
print 'Within last week'
else
print 'Not within last week'