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.
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
dateadd(mm, DATEPART(MONTH, DATE) - 1, 0) + DATEPART(DAY, DATE) - 1
OUTPUT date is in the year for example 1990-12-02 00:00:00:000
Full query is below:
SELECT dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0) + dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0) + DATEPART(DAY, GP_DATE) - 1 GP_DATE
from table
I am trying to convert this query into snowflake syntax and snowflake syntax dateadd function does not allow 1, 0.
In SQL Server, there are some rather ugly implicit conversions available between datetimes and integers.
0, when converted to a date, becomes 1900-01-01.
You're also allowed to do maths on dates. Adding or subtracting 1 adds or subtracts 1 day from the date. Putting these facts together, we have:
dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0)
Which is taking the current year, and subtracting 1900 from it (or 1899 if the month is less than 11, for whatever reason). We then take that number and add it back to the date 0 (which as stated above is 1900-01-01). The result is that we get the first of January of next year or this year, depending on the month of GP_DATE. Call this D1.
Moving on:
dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0)
is taking the month of GP_DATE, subtracting 1 from it and adding that number of months to the date 0 (1900-01-01). The result is a the 1st of whichever month GP_DATE is in, but in 1900. Let's call this D2.
When we add D1 and D2 together, we approximately get a date of the 1st of whichever month GP_DATE is in, in either this year or next year. Note, however, that this goes wrong if the D1 year is a leap year, we get it wrong by a day for months after February.
Finally, we take DATEPART(DAY, GP_DATE) - 1, where we take the day of the month from GP_DATE, subtract 1, and add that on to our result so far. This should set the final date to be on the same day of the month as GP_DATE, except for the error mentioned above.
So, it appears that the code is trying to take GP_DATE and get the same date in either this year or next year, depending on how late in the year GP_DATE is. However, it also appears it was never tested with consideration for leap years.
A far more likely correct version of this query would be this instead:
SELECT
DATEADD(year,
DATEDIFF(year,GP_DATE,CURRENT_TIMESTAMP) +
CASE WHEN DATEPART(month,GP_DATE)>10 THEN 0 ELSE 1 END
,GP_DATE)
I want to know the SQL Server query in which I can get record from the table against the specific day (like Monday OR Tuesday) of current week, OR against the specific day from the last 7 days.
Like I want to get record for 1st day of last 7 days OR Like I want to get record for the Monday OR Tuesday from current week.
By the way I can get specific day of current week through this SQL Server query
//Query
SELECT DATEADD(DD, 0 - DATEPART(DW, GETDATE()), GETDATE()) //Get Sunday
SELECT DATEADD(DD, 1 - DATEPART(DW, GETDATE()), GETDATE()) //Get Monday
SELECT DATEADD(DD, 2 - DATEPART(DW, GETDATE()), GETDATE()) //Get Tuesday
But I want to get record from the table against these days, like so:
Select * from tbl_Sale where date = "Here the specific day's date should be called"
Sorry for the long text but I really need to explain that what I need to do, so please if anyone can do this?
Return only those records where date is in the last 7 days and then further restrict your criteria to just Mondays.
SELECT *
FROM tbl_Sale
WHERE DATEDIFF(DAY, GETDATE(), date) BETWEEN -7 AND 0
AND DATENAME(WEEKDAY, date) = 'Monday'
This would also work.
SELECT *
FROM tbl_Sale
WHERE DATEDIFF(DAY, GETDATE(), date) BETWEEN -7 AND 0
AND DATEPART(WEEKDAY, date) = 2 -- by default 2 is equivalent to Monday
You will find a lot of valuable information reading up on Date and Time Data Types and Functions (Transact-SQL). So by default, DATEPART(WEEKDAY, date) will return 1 for any Sunday, 2 for any Monday, etc. However, you can set the first of the week to be whatever day you want by setting DATEFIRST.
Here is some sample code to show the Weekday Names and Weekday Numbers for a range of dates.
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()),
GETDATE())), 0),'First Monday of Current Month'
This query returns the first Monday of the current month. I just want to know how this query is working and how do I get the first Wednesday of the current month instead.
Let's simplify the whole:
SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()), GETDATE())), 0)
you can think at it in this way:
-- number of day to go back to reach 1st week of month
z = 6 - DATEPART(DAY, GETDATE())
-- a day in 1st week of the month
y = DATEADD(DAY, z, GETDATE())
-- number of weeks between 0 (1900-01-01) and 1st week of month
x = DATEDIFF(WEEK, 0, y)
-- add the number of weeks elapsed to 1900-01-01 to get the datetime of 1st day of 1st week of month
SELECT DATEADD(WEEK, x, 0)
I just want to know how this query is working
SELECT DATENAME(WEEKDAY, '1900-01-01') --'Monday'
SELECT DATENAME(WEEKDAY, 0) --also 'Monday'
January 1, 1900 was a Monday. When you add a week to a Monday you get another Monday. If you add 6,170 weeks to a Monday- you still get a Monday. As of 04/10/2018 there have been 6,170 weeks since Jan 1, 1900.
Simply, the query calculates these weeks, adding 6,170 weeks since Monday, Jan 1 1900.
how do I get the first Wednesday of the current month instead?
SELECT DATENAME(WEEKDAY, '1900-01-03') --Wednesday
SELECT DATENAME(WEEKDAY, 2) --also Wednesday
January 3, 1900 is represented by integer 2. We changed a 0 (which was monday) to a 2 (wednesday). If you add 6,170 weeks to a Wednesday you still get a Wednesday.
In the query there is a 0. We can change this to a 2:
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()),
GETDATE())), 2),'First Wednesday of Current Month'
Edit: I can make this perhaps a little clearer by getting rid of the integer and putting in the actual date:
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()),
GETDATE())), '1900-01-03'),'First Wednesday of Current Month'
This will give you the first Wednesday of the month, as requested in your comment:
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()), GETDATE())), 2)
AS 'First Wednesday of Current Month'
I changed your last 0 in the DATEADD function to a 2, as this is a zero based representation of the days of the week, 0 being Monday.
You can use the "Try it yourself" functionality on W3schools to play around with queries and figure them out: W3schools. Just paste your query in the console.
I tried many formula to get first Wednesday of the current month including above scripts but they were not working right if the month starts with Wednesday. (2022-06-01 can be tried). So I succeed it with my own way, you can see the sql below.
select
FirstWednesdayofCurrentMonth =
case when datepart(dw,EOMONTH(dateadd(month,-1,getdate()))) = 3
then dateadd(dd,1,EOMONTH(dateadd(month,-1,getdate()))) -- if month start with wednesday
else convert(date, DATEADD(DAY,(DATEDIFF(DAY,2,DATEADD(d,1,EOMONTH(dateadd(month,-1,getdate())))) / 7) * 7 + 7, 2)) -- if not
end
I need to create a report that looks like the following ("WE" is week-ending Sun to Sat):
SEPT.
WE 9/10 WE 9/17 WE 9/24 WE 10/1
Metric#1 40 49 58 40
Metric#2 24 25 20 1
The above may not be correct, it's just an example of the format.
My issue is I don't know which weeks correspond to which months. For example, the week of Oct 30 to Nov 5, I don't know which month it belongs to.
They've given me flexibility on how to do this. As long as it's consistent, it should ok.
I could also use the month of that week's Sunday (oct 30- nov-5 would be an October week because Oct 30 is a Sunday).
Could use some help here on figuring out how to assign a week to a particular month. I can do the pivoting, it's the date logic that I'm not sure about. The report is for the past 3 months.
SQL Server 2008. Report will be in SSRS 2008 R2
edit: Just got the requirements from the client. The month that has the most number of days in that week. For example Aug 28 to sept 3, for that week there are 4 days in August and 3 days in Sept, so that week belongs in August. I'll see if I can work this out.
You can use dates of Wednesdays to determine which months the corresponding weeks belong to. Your query might look something like this:
WITH marked AS (
SELECT
*,
WednesdayDate = DATEADD(DAY, 4 - DATEPART(WEEKDAY, DateColumn), DateColumn)
FROM atable
),
grouped AS (
SELECT
WeekYear = YEAR(WednesdayDate),
WeekMonth = MONTH(WednesdayDate),
WeekEnding = DATEADD(DAY, 3, WednesdayDate),
Metric1 = AGG(...),
Metric2 = AGG(...),
...
FROM marked
GROUP BY WednesdayDate
)
SELECT *
FROM grouped
WHERE WeekYear = ...
AND WeekMonth = ...
Your next step would probably be dynamic pivoting.
A problem like this is best solved with a calendar table: http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html
Basically, you build a table of days (10 years of days is only 3652 rows), and you associate each date with the week you want to assign it.
Your additional requirement means that the month of the week will always be the month of the week's Wednesday (since you have Sun-Sat weeks.)
So something like this will get you the month for any date:
DECLARE #TestDate DATETIME
SET #TestDate = 'October 31, 2011'
SELECT
DATEADD(week, DATEDIFF(week, 0, #TestDate), 2) AS WednesdayOfWeek, -- This is Wednesday of the week.
DATEPART(MONTH, DATEADD(week, DATEDIFF(week, 0, #TestDate), 2)) AS MonthNum,
DATENAME(MONTH, DATEADD(week, DATEDIFF(week, 0, #TestDate), 2)) AS MonthName,
DATEADD(MONTH, DATEDIFF(MONTH, 0, DATEADD(week, DATEDIFF(week, 0, #TestDate), 2)), 0) AS FirstOfMonth