SELECT previous year up to current date - sql

I have a table which has a Start Date column for example:
Start Date
2015/01/05
2015/02/08
2016/01/10
2017/02/10
etc...
I am trying to put into my WHERE clause to select all records where it is one year prior based on the current GETDATE().
For example, if today is July 2019 and I run the query, I'd like for it to run and give me Start Dates starting from July of 2018 up until June of 2019. And if I run it for August of 2019, I'd like for it to show Start Dates from August of 2018 up until July of 2019, and so on. Basically up until the month before of the current date.
Currently I have this in my WHERE clause:
WHERE start_date between DATEADD(YEAR,-1, GETDATE()) and GETDATE()
but this appears I believe to get just one year prior up until the current date exact.
Is there a better way for me to do this?

I think that this is your requirement:
WHERE start_date BETWEEN
DATEFROMPARTS(YEAR(GETDATE()) - 1, MONTH(GETDATE()), 1)
AND
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), -1)
With:
DATEFROMPARTS(YEAR(GETDATE()) - 1, MONTH(GETDATE()), 1)
you get the 1st day of current month in last year.
With:
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), -1)
you get the last Day of previous month.
See the demo.

You can use datefromparts() in SQL Server:
where start_date >= datefromparts(year(getdate()) - 1, 1, 1) and
start_date < datefromparts(year(getdate() - 1, month(getdate()), day(getdate())

Related

SQL get previous month (in January too)

Hello I'm looking for simple way, how to get data from previous month. I get this code but it didn't work in January (result is 12 2021 and I need 12 2020)
select month(dateadd(month,-1,getdate())), year(getdate())
Presumably, you have some sort of date column.
In SQL Server, you can express this concept using datediff():
where datediff(month, datecol, getdate()) = 1
However, that is not "sargable", meaning that it prevents the use of indexes. So, I would instead recommend:
where datecol < datefromparts(year(getdate()), month(getdate()), 1) and
datecol >= dateadd(month, 1, datefromparts(year(getdate()), month(getdate()), 1))
If you simply want the first day of the previous month, you can use:
dateadd(month, 1, datefromparts(year(getdate()), month(getdate()), 1))
Try This
select CASE WHEN month(getdate())>1 THEN month(getdate())-1 ELSE 12 END ,
CASE WHEN month(getdate())>1 THEN YEAR (getdate()) ELSE YEAR (getdate()) -1 END
Using the answer given here: How can I select the first day of a month in SQL?
SELECT dateadd(month,-1,DATEADD(month, DATEDIFF(month, 0, getdate()), 0)) as previousmonth;
output:
2020-12-01 00:00:00.000
I can provide next query using FORMAT function:
SELECT
-- get current day in previous month
FORMAT(dateadd(month, -1, getdate()), 'yyyy-MM-dd') as current_previousmonth,
-- get first of previous month
FORMAT(dateadd(month, -1, getdate()), 'yyyy-MM-01') as first_previousmonth,
-- previous month without date
FORMAT(dateadd(month, -1, getdate()), 'yyyy-MM') as previousmonth;
test T-SQL here
Here you go!
select dateadd(mm,-1,eomonth(getdate())) as [Previous Month]
Result:
Previous Month
--------------
2020-12-31
You could also use CONVERT() or FORMAT() functions to format the date as you desire.
Try
SELECT FORMAT(DATEADD(month, -1, GETDATE()),'MM/yyyy');
It will give you previous month and the year. If you are comparing to a date column in a existing table, then you need the date part too as you want to know December of which year was the previous month. But if you don't want the year, then just adjust the 'MM/yyyy' part to suit your purpose.

Is there a way to set relative start and end dates in SQL for last 4 complete months and current month to date?

If applied to today, I want to return values for 1/10/19 through 25/02/20.
I am using the below currently, but wish to replace it with something that gives me 4 complete months and the current partial month
where DATEDIFF (day,[SubOrderCompletionDate],GETDATE()) between 0 and 180
Thanks
If you want complete months, just change this to:
where DATEDIFF(month, SubOrderCompletionDate, GETDATE()) between 0 and 3
DATEDIFF() counts the number of boundaries between two dates. So, all days within a given calendar month return the same value.
I've taken your statement literally, and therefore assumed that if today was 29 February 2020 you would want 1 November 2019 to 29 February 2020, not 1 October 2019 to 29 Feburary 2020:
SELECT * --This should be a column list, not *
FROM dbo.YourTable YT
WHERE YT.SubOrderCompletionDate >= CASE WHEN EOMONTH(GETDATE()) = CONVERT(date,GETDATE()) THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 3,0) ELSE DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 4,0) END
AND YT.SubOrderCompletionDate <= GETDATE()
If that isn't the case, you just need DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 4,0), which will give you 5 months worth of data.

Last Day of Each Month Calculation

I have a table X which holds data for each day for a brand. The data for each day is cumulative i.e. sales data for 3 will have data for 1, 2 and 3. Thus data for the last day of each month will be the sales for that month for that brand and company. I want to get the sum of all the sales for that brand for the last 3 months excluding the current month on the last day of each month.
i.e for March: I want sales from 31st Jan 2019 + 28th Feb 2019 + 31st Dec 2018 for each brand and company.
How can I achieve this?
if you are using MSSQL you can use EOMONTH function, example is as under
DECLARE #date VARCHAR(255) = '2/24/2019';
SELECT EOMONTH ( #date ) AS Result;
for MySQL you can use LAST_DAY function
SELECT LAST_DAY('2019-02-24');
Let's say name of your column representing the sales date is "sales_date", then the following predicate will give you the days you're interested in:
sales_date in (
dateadd(day, -1, dateadd(month, datediff(month, 0, getdate()) - 2, 0)),
dateadd(day, -1, dateadd(month, datediff(month, 0, getdate()) - 1, 0)),
dateadd(day, -1, dateadd(month, datediff(month, 0, getdate()), 0))
)

SQL - pick current date from machine and compare with previous week

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 to create list of weeks corresponding to a month in SQL?

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