SQL Server 2008 Rolling Average - sql

I am trying to create a SQL statement to calculate a 6 month rolling average for my data. I am following this guide:
SQL Query for 7 Day Rolling Average in SQL Server
but the problem is I am using SQL Server 2008 and the answer here is for 2012.
select
x.*,
avg(dailyusage) over(partition by productid order by productid, date rows between 6 preceding and current row) as rolling_avg
from
(select
productid, date, sum(usagecount) as dailyusage
from tbl
group by productid, date) x
It will be appreciated if someone can help me translate it over to 2008 terms.
Thanks

You could try to use OUTER APPLY, but it won't be as efficient:
;WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY productid ORDER BY [date]) RN
FROM ( SELECT productid, [date], SUM(usagecount) dailyusage
FROM dbo.YourTable
GROUP BY productid, [date]
) t
)
SELECT TOP 100 *
FROM CTE A
OUTER APPLY(SELECT AVG(dailyusage) rolling_avg
FROM CTE
WHERE productid = A.productid
AND A.RN - RN BETWEEN 0 AND 6) B;

Related

How to get min value at max date in sql?

I have a table with snapshot data. It has productid and date and quantity columns. I need to find min value in the max date. Let's say, we have product X: X had the last snapshot at Y date but it has two snapshots at Y with 9 and 8 quantity values. I need to get
product_id | date | quantity
X Y 8
So far I came up with this.
select
productid
, max(snapshot_date) max_date
, min(quantity) min_quantity
from snapshot_table
group by 1
It works but I don't know why. Why this does not bring min value for each date?
I would use RANK here along with a scalar subquery:
WITH cte AS (
SELECT *, RANK() OVER (ORDER BY quantity) rnk
FROM snapshot_table
WHERE snapshot_date = (SELECT MAX(snapshot_date) FROM snapshot_table)
)
SELECT productid, snapshot_date, quantity
FROM cte
WHERE rnk = 1;
Note that this solution caters to the possibility that two or more records happened to be tied for having the lower quantity among those most recent records.
Edit: We could simplify by doing away with the CTE and instead using the QUALIFY clause for the restriction on the RANK:
SELECT productid, snapshot_date, quantity
FROM snapshot_table
WHERE snapshot_date = (SELECT MAX(snapshot_date) FROM snapshot_table)
QUALIFY RANK() OVER (ORDER BY quantity) = 1;
Consider also below approach
select distinct product_id,
max(snapshot_date) over product as max_date,
first_value(quantity) over(product order by snapshot_date desc, quantity) as min_quantity
from your_table
window product as (partition by product_id)
use row_number()
with cte as (select *,
row_number() over(partition by product_id order by date desc) rn
from table_name) select * from cte where rn=1

Filter SQL Server Records by Latest Date on Every Year

How would I filter this SQL server database so only the green records are left aka the last recorded date every year for each Customer ID field.
If you want to get the rows, not only the date values, using ROW_NUMBER() is an option (you only need to use the appropriate PARTITON BY and ORDER BY clauses):
SELECT *
FROM (
SELECT
CustomerId,
[Date],
ROW_NUMBER() OVER (PARTITION BY CustomerId, YEAR[Date] ORDER BY [Date] DESC) AS Rn
FROM YourTable
) t
WHERE Rn = 1
To check the maximum date in the year, you can write a query to get for each year the date where not exists another (in the same year), as follow:
SELECT *
FROM yourtable t1
WHERE NOT EXISTS
(SELECT 1
FROM yourtable t2
WHERE t1.customerID = t2.customerID
AND t1.date > t2.date
AND DATEPART(YEAR, t1) = DATEPART(YEAR, t2))
If you have only two columns, then you can just use aggregation:
select customer_id, max(date)
from t
group by customer_id, year(date);

Running Total in SQL including last year end total

Need a query to select "Running Total" as mentioned in the image
2017 year end total plus Every months new figure should add up to previous total.
https://i.stack.imgur.com/DL7p0.png "Example"
This following script will work for MSSQL and you can use the same logic for other databases as well-
WITH your_table(year,month,partersgrowth)
AS
(
SELECT '2019','jan', 100 UNION ALL
SELECT '2019','feb', 300 UNION ALL
SELECT '2019','mar', 400 UNION ALL
SELECT '2019','apr', 500 UNION ALL
SELECT '2018','Dec', 200
)
SELECT A.year,A.month,A.partersgrowth,
(
SELECT SUM(B.partersgrowth)
FROM your_table B
WHERE CAST(B.Year +'-'+B.month+'-01' AS DATE)
<= CAST(A.Year +'-'+A.month+'-01' AS DATE)
) Running_Total
FROM your_table A
ORDER BY CAST(A.Year +'-'+A.month+'-01' AS DATE)
using #mkRabbani solution.. you can simplify it like this:
;WITH your_table(year,month,partersgrowth)
AS
(
SELECT '2019','jan', 100 UNION ALL
SELECT '2019','feb', 300 UNION ALL
SELECT '2019','mar', 400 UNION ALL
SELECT '2019','apr', 500 UNION ALL
SELECT '2018','Dec', 200
)
select *, sum(partersgrowth) over ( order by [year],[month]) as running_total
from your_table
EDIT: As pointed out by comment below.. you want to order by a proper date in the sum part ( I would use order by year and then the month number rather than the month name)
If you use MSSQL you can run the following code
with cte as (
select t.*, lag(partersGrowth) over(partition by year order by month asc rows ROWS UNBOUNDED PRECEDING) prevTotal
from Table )
select years, month, partersGrowth, prevTotal || '+' partersGrowth as "Need Running Total"
from cte

How to calculate date difference between different visits using SQL

I want to calculate the day difference between first visit and the second visit; second visit and third visits etc. per customer using SQL. Please assist.
For example, Customer A visited three times on
2016-01-03, 2016-01-06 and 2016-05-30 while customer B visited ten times with different dates.
Query
With cte as (Select customerid, VisitDate,
ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY VisitDate) as rownum
FROM visitTable V)
Select CustomerID, VisitDate, rownum, DateDiff(D,R1.VisitDate, R2.VisitDate) as NoOfDays
FROM cte R1
LEFT JOIN cte R2 ON R1.CustomerID = R2.CustomerID AND R1.rownum = 1 AND R2.rownum = 2
Thank you
I think you were pretty close to the right idea. Your join needs to compare row numbers. I also switched the order of your date diff but I didn't test it.
With cte as (
Select customerid, VisitDate,
ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY VisitDate) as rownum
FROM visitTable V
)
Select R1.CustomerID, R1.VisitDate, R1.rownum,
DateDiff(D,R2.VisitDate, R1.VisitDate) as NoOfDays --this is days since last visit
FROM cte R1 --current row
LEFT JOIN cte R2 --previous visit - will result in null days for 1st row.
ON R1.CustomerID = R2.CustomerID
AND R1.rownum - 1 = R2.rownum
order by R1.CustomerID, R1.VisitDate;

SQL- Trying to subtract date values from the same column

I need a subtraction of a max date to the last previous status date and cannot figure it out. I will be using FindingID and UpdatedEstimatedRemediationDate.
For example:
FindingID 'FND-5645' has been updated 3 times:
UpdatedEstimatedRemediationDate
--------------------------------
NULL
2015-06-15
2015-12-30
2016-06-30
I need to get the days difference from June 30, 2016 from December 12,2015. I am using SQL Server 2008 R2. Thanks in advance.
If I understand correctly, this is basically an aggregation query with datediff():
select findingid, datediff(day, min(UpdatedEstimatedRemediationDate), max(UpdatedEstimatedRemediationDate)
from t
group by findingid;
You can use ROW_NUMBER() to partition by FindingId and order by UpdateDate desc, pick first and last dates and have the date diff in days:
Setup:
-- drop table UpdatedEstimatedRemediationDate
create table UpdatedEstimatedRemediationDate
(
FindingId INT,
UpdateDate DATE
)
insert into UpdatedEstimatedRemediationDate values
(1, '2015-06-15'), (1, '2015-12-30'), (1, '2016-06-30'), (2, '2015-07-13'), (2, '2016-05-01')
GO
Query:
;WITH Cte AS (
SELECT FindingId, UpdateDate, ROW_NUMBER() OVER (PARTITION BY FindingId ORDER BY UpdateDate DESC) AS RowNo
FROM UpdatedEstimatedRemediationDate
)
SELECT LU1.FindingId, DATEDIFF(day, LU1.UpdateDate, LU2.UpdateDate) AS DaysDiff
FROM Cte LU1
JOIN Cte LU2 ON LU2.FindingId = LU1.FindingId AND LU1.RowNo = 2 AND LU2.RowNo = 1
[no self join version]
For SQL Server 2012, SELF JOIN may be avoided using LAG/LEAD function:
WITH CTE AS (
SELECT FindingId, DATEDIFF(day, UpdateDate, LEAD(UpdateDate, 1, NULL) OVER (PARTITION BY FindingId ORDER BY UpdateDate)) DayDiff,
ROW_NUMBER() OVER (PARTITION BY FindingId ORDER BY UpdateDate DESC) RowNo
FROM UpdatedEstimatedRemediationDate)
SELECT CTE.FindingId, CTE.DayDiff
FROM CTE
WHERE RowNo = 2