Rolling n-day aggregation conditional on another column - sql

struggling to figure out how to implement a code that will allow me to calculate following (using SQL in BigQuery) in an elegant way.
I'd need to calculate a rolling n-day aggregation (let's assume rolling 3-day sum of units ) for each date but only taking into account data that where the price is less than a certain value (let's assume 50).
So based on below table
date
price
units
01-21
30
200
01-22
100
500
01-23
20
200
01-24
20
100
01-25
80
100
01-26
40
250
I'd need my query to return:
date
units
01-21
200
01-22
200
01-23
400
01-24
300
01-25
300
01-26
350
Struggling to figure out how to combine window calculations with the additional conditions.
Thanks in advance!

Consider below approach
select date, sum(if(price < 50, units, 0)) over win units
from your_table
window win as (order by unix_date(date) range between 2 preceding and current row)
if applied to sample data as in your question -
with your_table as (
select date '2022-01-21' date, 30 price, 200 units union all
select '2022-01-22', 100, 500 union all
select '2022-01-23', 20, 200 union all
select '2022-01-24', 20, 100 union all
select '2022-01-25', 80, 100 union all
select '2022-01-26', 40, 250
)
the output is

Related

Monthly cumulative differences calculation in postgres

I am trying to write an sql script in postgres that find cumulative difference in total price and repayment amount. I have two tables as shown below. I have gone through solution provided here but it doesn't address my question.
item table
item_id cost_price date_purchase
1 200 01-06-2019
2 300 10-07-2019
3 250 15-08-2019
4 400 10-09-2019
payment table
item id payment payment date
1 50 01-06-2019
1 40 20-06-2019
2 30 15-07-2019
1 60 17-07-2019
2 100 15-08-2019
3 90 17-08-2019
4 300 20-09-2019
1 50 25-09-2019
Expected result
Month Remaining amount
06_2019 (200 - 90) = 110
07_2019 (200+ 300) - (90 + 30 + 60) = 320
08_2019 (200+ 300 + 250) - (90 + 90 + 100 + 90) = 380
09_2019 (200 + 300 + 250 + 400) - (90 + 90 + 190 + 300 + 50) = 430
You can do that by SUMs with WINDOWING function that's uses ORDER BY month. But give us the DDL of your table to be helped more...
Since your example ignores the item_id in the results, you can combine purchases and payments into a simple ledger and then use a window function to get a running sum:
with ledger as (
select to_char(date_purchase, 'YYYY-MM') as xact_month, cost_price as amount from item
union all
select to_char(payment_date, 'YYYY-MM'), payment * -1 from payment
)
select distinct xact_month as month,
sum(amount) over (order by xact_month) as remaining_amount
from ledger;
Working fiddle.
This is it:
select distinct date_trunc('month',m.date_1),m.num_1 from (select to_date(b."payment date",'DD-MM-YYYY') as date_1,
sum(a."cost_price"+coalesce((select sum("cost_price") from item_table c where
date_trunc('month',to_date(a."date_purchase",'DD-MM-YYYY'))>date_trunc('month',to_date(c."date_purchase",'DD-MM-YYYY'))
),0)-(coalesce((select sum("payment") from payment_table c where
date_trunc('month',to_date(a."date_purchase",'DD-MM-YYYY'))>=date_trunc('month',to_date(c."payment date",'DD-MM-YYYY'))
),0))) as num_1 from item_table a,payment_table b
where date_trunc('month',to_date(a."date_purchase",'DD-MM-YYYY'))
=date_trunc('month',to_date(b."payment date",'DD-MM-YYYY'))
group by 1 order by 1)m;
please check at http://sqlfiddle.com/#!17/428874/37
possibly give it a green tick and an upvote..

Sum Amount Per Month Between Date Ranges

I have a table that stores scheduled charges within a date range. I am looking to sum the values per month, but am unsure how to structure the query to handle the range logic. A simplified version of the table structure is below where dates are in MM/DD/YYYY format:
Start End Amount
01/15/2020 04/30/2020 200
02/05/2020 06/30/2020 300
03/01/2020 12/15/2020 400
04/02/2020 10/25/2020 500
The output would display a sum for every month there are records for based on an entry existing in the Start or End column for that month. So the output would look like this:
Month Amount
01/2020 200
02/2020 500
03/2020 900
04/2020 1400
05/2020 1200
06/2020 1200
07/2020 900
08/2020 900
09/2020 900
10/2020 900
11/2020 500
12/2020 500
Any ideas of how to handle this without a separate table storing each month/year to check if it is within the range?
You can use a recursive CTE and then aggregate:
with cte as (
select datefromparts(year(start), month(start), 1) as dte, end, amount
from t
union all
select dateadd(month, 1, dte), end, amount
from cte
where eomonth(dte) < eomonth(end)
)
select dte, sum(amount)
from cte
group by dte;
Here is a db<>fiddle.

MS-Access : How to sum multiple values from different tables according to dates

I have two similar tables as follows
Table 1
Date Amount Tax
4/1/2016 1000 100
4/1/2016 2000 200
5/3/2016 1500 150
5/6/2016 1000 100
5/6/2016 3000 300
7/9/2016 2500 250
Table 2
Date Amount Tax
4/1/2016 1000 100
4/2/2016 3000 300
5/3/2016 1500 150
5/9/2016 4000 400
8/11/2016 3000 300
10/9/2016 2000 200
dates can be similar or different in both tables.
I want two queries.
First, a query which gives me sum of amount and tax from each date from both tables between required dates. Eg: Table 1 have 2 entries and table 2 have 1 entry for 4/1/2016. so the result should be as below (summing up all three entries)
Date Amount Tax
4/1/2016 4000 400
4/2/2016 3000 300
5/3/2016 3000 300
5/6/2016 4000 400
5/9/2016 4000 400
7/9/2016 2500 250
8/11/2016 3000 300
10/9/2016 2000 200
Second,a query which gives of sum of amount and tax for each month from both tables between required dates. Eg output as below
Date Amount Tax
4/2016 4000 400
5/2016 11000 1100
7/2016 2500 250
8/2016 3000 300
10/2016 2000 200
Query that have I have written till now( not working )
SELECT date, sum(Amount),sum(Tax)
From Table1
WHERE Date BETWEEN #04/01/2016# AND #12/31/2016#
UNION ALL
SELECT date, sum(Amount),sum(Tax)
From Table2
WHERE Date BETWEEN #04/01/2016# AND #12/31/2016#
GROUP BY Date
For first query, consider a union query derived table with outer query aggregation:
SELECT q1.[Date], SUM(q1.Amount) AS DayTotalAmt, SUM(q1.Tax) AS DayTotalTax
FROM
(SELECT [Date], Amount, Tax
FROM Table1
UNION ALL
SELECT [Date], Amount, Tax
FROM Table2
) AS q1
GROUP BY q1.[Date]
For second query, consider using first query as a source with another outer query layer that runs a WHERE filter with month/year aggregation:
SELECT Format(q2.Date, "M/YYYY"), SUM(q2.DayTotalAmt) AS MonthTotalAmt,
SUM(q2.DayTotalTax) AS MonthTotalTax
FROM
(SELECT q1.[Date], SUM(q1.Amount) AS DayTotalAmt, SUM(q1.Tax) AS DayTotalTax
FROM
(SELECT [Date], Amount, Tax
FROM Table1
UNION ALL
SELECT [Date], Amount, Tax
FROM Table2) AS q1
GROUP BY q1.[Date]
) AS q2
WHERE q2.Date BETWEEN CDate("4/1/2016") AND CDate("12/31/2016")
GROUP BY Format(q2.Date, "M/YYYY")
Or if you save first query:
SELECT Format(q.Date, "M/YYYY"), SUM(q.DayTotalAmt) AS MonthTotalAmt,
SUM(q.DayTotalTax) AS MonthTotalTax
FROM Query1 q
WHERE q.Date BETWEEN CDate("4/1/2016") AND CDate("12/31/2016")
GROUP BY Format(q.Date, "M/YYYY")

select monthly report where per day transction show in single row

Date - Amount
12-nov-2016 200
12-nov-2016 100
13- nov -2016 400
13 -nov-2016 200
result show like-
Date Amount
12- nov-2016 300
13- nov-2016 600
as whole month
select [Date], sum(Amount) as Amount from yourTable group by [Date]

avg of multiple columns

I would like to find the avg of multiple columns instead of rows.
At present, I transposed the table but that's impacting the performance as my table is very big and by transposing 30 columns the number of rows increased * 29 times.
colum1 measure1 measure2 measure3 avg
abc 100 200 300 200
def 50 60 70 60
I am not going to use all the 30 columns at a time for average and it depends on my parameters in the front end.
I would like to know if there any other solutions to achieve the desired result other than transpose.
In Redshift, I am doing a union of table 29 times to transpose columns to rows.
Your advises would be highly appreciated.
Thanks,
mc
Try something like this (Oracle query):
WITH input_data AS (
SELECT 100 AS measure1, 200 AS measure2 FROM DUAL
UNION ALL
SELECT 1000 AS measure1, 2000 AS measure2 FROM DUAL
)
SELECT (a.measure1 + a.measure2) / 2 AS measure_avg FROM input_data a
Output:
MEASURE_AVG
150
1500