SQL how to get information from The Start of some # of years ago - sql

I have looked through a few posts but either there is too much information or I just don't quite understand what I am looking for.
eg: How to get the first and last date of the current year?
In a table I have sales orders for the last 20 years, all I want is to show the orders from January 1st of three years before until whatever the current date is.
AND ShipDate >= (YEAR(ShipDate)-3)
Which doesn't work.
AND ShipDate >= DATEADD(YEAR,-2,GETDATE())
Which Shows exactly 2 years ago from whatever the current day is.
I want to be able to eventually create reports that show each year in the last three on their own but this is the first step and I am not doing well so far!

I want is to show the orders from January 1st of three years before until whatever the current date is.
The best method in SQL Server is:
where shipdate >= datefromparts(year(getdate()) - 3, 1, 1)
For any date in 2021, this returns all rows from 2021, 2020, 2019, and 2018. If you don't want 2018, then use - 2 rather than - 3.
This formulation has the option of being optimizer friendly (allowing the use of indexes and partitions, for example). Two other common says to write this are not optimizer friendly:
where datediff(year, shipdate, getdate()) <= 3
where year(shipdate) >= year(getdate()) - 3
(Once again, the "3" might be "2" depending on what you really intend.)

you were close:
AND YEAR(ShipDate) >= (YEAR(ShipDate)-3)
You were comparing a year to a date

Related

SQL - Count month difference in non-consecutive date period

I am trying to extract how many months of membership a member gets up to date. As the picture shows, this member got four years of subscription since 2018. However, she stopped the subscription for a year ending in 2019. And then, restart the membership in 2020 again.
Each membership lasts for 12 months. if we look at the last membership starting from 2022-05-08, it will end up on 2023-05-08. However, I only want to get the total month count up to date(getdate - 2022-09-14).
Please advise how I could approach this matter. Thanks!
enter image description here
Assuming you were planning to apply sum(monthcount), you could wrap the monthcount within a CASE statement to checks if the vip_end is greater than today's date:
sum(case when vip_end > getdate() then ... else monthcount end)
What you do within that ... depends on whether you wanted to just count the different number of months within the date range (e.g. 31st Jan -> 01st Feb is counted as a whole month because it just considers Jan -> Feb):
datediff(month, datecreated, getdate())
or perhaps calculate the number of months based on the average days in a month:
datediff(day, datecreated, getdate())*12.0/365.25
or maybe something else... it really depends on what level of detail you want to achieve.

Oracle Week Number from a Date

I am brand new to Oracle. I have figured out most of what I need but one field is driving me absolutely crazy. Seems like it should be simple but I think my brain is fried and I just can't get my head around it. I am trying to produce a Sales report. I am doing all kinds of crazy things based on the Invoice Date. The last thing I need to do is to be able to create a Week Number so I can report on weekly sales year vs year. For purposes of this report my fiscal year starts exactly on December 1 (regardless of day of week it falls on) every year. For example, Dec 1-7 will be week 1, etc. I can get the week number using various functions but all of them are based on either calendar year or ISO weeks. How can I easily generate a field that will give me the number of the week since December 1? Thanks so much for your help.
Forget about the default week number formats as that won't work for this specific requirement. I'd probably subtract the previous 1 December from invoice date and divide that by 7. Round down, add 1 and you should be fine.
select floor(
(
trunc(invoiceDate) -
case
-- if December is current month, than use 1st of this month
when to_char(invoiceDate, 'MM') = '12' then trunc(invoiceDate, 'MM')
-- else, use 1st December of previous year
else add_months(trunc(invoiceDate, 'YYYY'), -1)
end
) / 7
) + 1
from dual;

Year Week column comparison

I have this query that spits out every Week for the past 2 years a company owes us money. I have to narrow the results down based on their starting year and week, which are 2 separate columns. This is my current query. How do I change this so it only shows data where the year is greater or equal to start year and the week is greater or equal to the start week without losing data? So for example if I have a company 023 and its start date is week 5 2012, I'll say year>=2012 and week>=5, but then it will exclude all the weeks in 2013 and 2014 where week is less than 5. I'm not sure how logically to get around that.
SELECT MW.MW_Weeks.Year,
MW.MW_Weeks.Week,
MW.MW_CompanyCodes.cmp_code,
MW.MW_CompanyCodes.stWeek,
MW.MW_CompanyCodes.stYear
FROM MW.MW_Weeks CROSS JOIN
MW.MW_CompanyCodes
WHERE (MW.MW_Weeks.WEDate <= GETDATE())
AND (MW.MW_Weeks.Year > YEAR(GETDATE()) - 2);
Use the following:
year >= 2012 and not (year = 2012 and week < 5)
This will get all data whose year is greater than or equal to 2012 and is not before week five in 2012.

Filter date to be greater than 24 months rather than 2 years?

This is what I have so far:
SELECT ListKey
FROM Closing_List
WHERE DATEPART(YEAR,closedate) > DATEPART(YEAR,GETDATE())-2)
But I want 24 Months back.
Thanks!
SELECT ListKey
FROM Closing_List
WHERE closedate > DATEADD(MONTH, -24, GETDATE())
SELECT ListKey
FROM Closing_List
WHERE closedate > DATEADD(MONTH,-24,GETDATE())
Using DATEADD is fine as long as you know what it's doing with the dates.
GetDate() returns the current date and time. Right now for me that's 08/30/2013 02:18:14pm
Passing that through DATEADD(MONTH,-24,GETDATE()) yields 08/30/2011 02:18:14pm'
So if I were running your query with that information it would be giving me all results with a closedate greater than (not equal to) 08/30/2011 02:18:14pm. There are a couple of things to consider about that.
For one, if you have records that closed on 08/30/2011 at 1:00pm then they won't be included in your results. Moreover if your close dates don't have times at all then you won't get any records from 08/30/2011.
Also note that if you run that query on 9/2/2013 then it won't include records from 9/1/2011. That may or may not be a problem, depending on your needs.
Another solution might be:
SELECT ListKey
FROM Closing_List
WHERE closedate >= dateadd(month,datediff(month,0,getdate())-24,0)
If you run the above anytime in September of 2013 it will include all records with a close date from September 2011 to September 2013. It doesn't care about what day of the month it currently is or if the close date includes time data.

T-SQL absence by month from start date end date

I have an interesting query to do and am trying to find the best way to do it. Basically I have an absence table in our personnel database this records the staff id and then a start date and end date for the absence. End date being null if not yet entered (not returned). I cannot change the design.
They would like a report by month on number of absences (12 month trend). With staff being off over the month change it obviously may be difficult to calculate.
e.g. Staff off 25/11/08 to 05/12/08 (dd/MM/yy) I would want the days in November to go into the November count and the ones in December in the December count.
I am currently thinking in order to count the number of days I need to separate the start and end date into a record for each day of the absence, assigning it to the month it is in. then group the data for reporting. As for the ones without an end date I would assume null is the current date as they are presently still absent.
What would be the best way to do this?
Any better ways?
Edit: This is SQL 2000 server currently. Hoping for an upgrade soon.
I have had a similar issue where there has been a table of start/end dates designed for data storage but not for reporting.
I sought out the "fastest executing" solution and found that it was to create a 2nd table with the monthly values in there. I populated it with the months from Jan 2000 to Jan 2070. I'm expecting it will suffice or that I get a large pay cheque in 2070 to come and update it...
DECLARE TABLE months (start DATETIME)
-- Populate with all month start dates that may ever be needed
-- And I would recommend indexing / primary keying by start
SELECT
months.start,
data.id,
SUM(CASE WHEN data.start < months.start
THEN DATEDIFF(DAY, months.start, data.end)
ELSE DATEDIFF(DAY, data.start, DATEADD(month, 1, months.start))
END) AS days
FROM
data
INNER JOIN
months
ON data.start < DATEADD(month, 1, months.start)
AND data.end > months.start
GROUP BY
months.start,
data.id
That join can be quite slow for various reasons, I'll search out another answer to another question to show why and how to optimise the join.
EDIT:
Here is another answer relating to overlapping date ranges and how to speed up the joins...
Query max number of simultaneous events