All answers posted here so far assume that the years in which the item was not used should not contribute to the average.
In other words, if the yearly usage is 10, 0, 10
, the answer you will get will be 10 (not 6.66).
If you have items that are listed in the inventory somewhere, but not actually being used in transactions, you will not get any answer for them (instead of getting the item id with a zero next to it).
This all might be actually what you want, or it might not be a problem for your system because most items are actually being used in every year since they've been introduced, and you don't care about occasional outliers. In this case, use any of the answers above.
If you want all the years and all the items to contribute to the average, even those that didn't have any transactions, use one of these queries below.
Fixed years
This query calculates the average of yearly consumption of every item in your system during a fixed time span. Since the system doesn't know what time span you want to calculate the average over (maybe you want the average yearly consumption of iPhones since 1900), you'll need to provide it to the query explicitly.
Note that when calculating yearly averages, you might want to omit records for the current year, as it still hasn't finished and is likely to skew your data.
SELECT i.Id, SUM(COALESCE(QuantityUsed, 0)) * 1. / DATEDIFF(year, '2014-01-01', GETDATE()) -- start of the time span you're interested in.
FROM Items i -- list of all the items in the system
LEFT JOIN
ItemTransactions it
ON it.ItemNumber = i.Id
AND it.DateUsed < DATETRUNC(year, GETDATE())
AND it.DateUsed >= '2014-01-01'
GROUP BY
i.Id
This will also give you the correct answer of zero for the items that have never been consumed in a transaction at all, instead of omitting them from the resultset.
First transaction as start date
You might want to treat the first transaction that happened with the item as the date of its introduction. In this case, use this:
SELECT i.Id, COALESCE(SUM(QuantityUsed) * 1. / DATEDIFF(year, MIN(DateUsed), GETDATE()), 0)
FROM Items i -- list of all the items in the system
LEFT JOIN
ItemTransactions it
ON it.ItemNumber = i.Id
AND it.DateUsed < DATETRUNC(year, GETDATE())
GROUP BY
i.Id
Actual dates
Your system might also be storing the actual dates of introduction and, possibly, discontinuation of each item. In this case, just put these dates into the DATEDIFF
function in the SELECT
clause.