How to get current and previous month's data in a table? - sql

I have a table in oracle db that contains product_id (unique) , month and price data.
MONTH
PRODUCT_ID
CURRENT_PRICE
2
00011
14
2
00022
60
3
00011
10
3
00022
40
I want to write a SQL code in oracle to build up the view shown below;
MONTH
PRODUCT_ID
CURRENT_PRICE
PREVIOUS_PRICE
CHANGE_RATE
2
00011
14
NULL
NULL
2
00022
60
NULL
NULL
3
00011
10
14
40
3
00022
40
60
50
where current and previous price datas for each product is listed in a one row. How can i write it down? Thanks in advance.

Use lag():
select t.*,
lag(current_price) over (partition by product_id order by month) as prev_price,
(-100 + lag(current_price) over (partition by product_id order by month) * 100.0 / current_price) as change_rate
from t
order by month, product_id;
Here is a db<>fiddle.

Related

Find most visited Hotel by month in PostgreSQL

I have a table with couple of customers resided in a hotel for a month or months. I need to find 3 most visited hotels by month. In case one customer lived in a hotel for three months, then it refers for three month. To be more precise below table hotel I have:
id
usr_id
srch_ci
srch_co
hotel_id
1
13
2021-10-01
2021-11-22
200
2
12
2021-10-11
2021-10-22
300
3
11
2021-10-28
2021-11-05
200
4
10
2021-10-28
2021-12-03
100
Result should look like below:
mnth
hotel_id
rnk
visits
2021-10
200
1
2
2021-10
100
2
1
2021-10
300
2
1
2021-11
200
1
2
2021-11
100
2
1
2021-12
100
1
1
As we can see above, user_id = 10 stayed in a hotel = 100 for 3 different months. That means it is counted for 3 different month for a hotel as 1 count. And for 2021-12 month only user = 10 stayed, for this reason in 2021-12 month hotel = 100 is ranked as 1st.
I solved problem using generate_series function in Postgres. That is what I was looking for. This link helped me. Splitting single row into multiple rows based on date
SELECT hotel_id,mnth,visits,
ROW_NUMBER() OVER (PARTITION BY mnth ORDER BY visits DESC) AS rnk FROM (
SELECT hotel_id,to_char(live_mnth,'YYYY-MM') AS mnth,count(*) AS visits FROM (
SELECT id,usr_id,hotel_id,date_in,date_out,
generate_series(date_in, date_out, '1 MONTH')::DATE AS live_mnth
FROM (
SELECT *,TO_CHAR(srch_ci, 'yyyy-mm-01')::date AS date_in,
TO_CHAR(srch_co, 'yyyy-mm-01')::date AS date_out
FROM hotels
) s
) s GROUP BY hotel_id,to_char(live_mnth,'YYYY-MM')
) t

How to calculate average monthly number of some action in some perdion in Teradata SQL?

I have table in Teradata SQL like below:
ID trans_date
------------------------
123 | 2021-01-01
887 | 2021-01-15
123 | 2021-02-10
45 | 2021-03-11
789 | 2021-10-01
45 | 2021-09-02
And I need to calculate average monthly number of transactions made by customers in a period between 2021-01-01 and 2021-09-01, so client with "ID" = 789 will not be calculated because he made transaction later.
In the first month (01) were 2 transactions
In the second month was 1 transaction
In the third month was 1 transaction
In the nineth month was 1 transactions
So the result should be (2+1+1+1) / 4 = 1.25, isn't is ?
How can I calculate it in Teradata SQL? Of course I showed you sample of my data.
SELECT ID, AVG(txns) FROM
(SELECT ID, TRUNC(trans_date,'MON') as mth, COUNT(*) as txns
FROM mytable
-- WHERE condition matches the question but likely want to
-- use end date 2021-09-30 or use mth instead of trans_date
WHERE trans_date BETWEEN date'2021-01-01' and date'2021-09-01'
GROUP BY id, mth) mth_txn
GROUP BY id;
Your logic translated to SQL:
--(2+1+1+1) / 4
SELECT id, COUNT(*) / COUNT(DISTINCT TRUNC(trans_date,'MON')) AS avg_tx
FROM mytable
WHERE trans_date BETWEEN date'2021-01-01' and date'2021-09-01'
GROUP BY id;
You should compare to Fred's answer to see which is more efficent on your data.

SQL sum and previous row [duplicate]

This question already has answers here:
Calculate a Running Total in SQL Server
(15 answers)
Closed 3 years ago.
I have the following table:
________________________
date | amount
________________________
01-01-2019 | 10
01-01-2019 | 10
01-01-2019 | 10
01-01-2019 | 10
02-01-2019 | 5
02-01-2019 | 5
02-01-2019 | 5
02-01-2019 | 5
03-01-2019 | 20
03-01-2019 | 20
These are mutation values by date. I would like my query to return the summed amount by date. So for 02-01-2019 I need 40 ( 4 times 10) + 20 ( 4 times 5). For 03-01-2019 I would need ( 4 times 10) + 20 ( 4 times 5) + 40 ( 2 times 20) and so on. Is this possible in one query? How do I achieve this?
My current query to get the individual mutations:
Select s.date,
Sum(s.amount) As Sum_amount
From dbo.Financieel As s
Group By s.date
You can try below -
DEMO
select dateval,
SUM(amt) OVER(ORDER BY dateval ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as amt
from
(
SELECT
dateval,
SUM(amount) amt
FROM t2 group by dateval
)A
OUTPUT:
dateval amt
01/01/2019 00:00:00 40
01/02/2019 00:00:00 60
01/03/2019 00:00:00 100
Try this below script to get your desired output-
SELECT A.date,
(SELECT SUM(amount) FROM <your_table> WHERE Date <= A.Date) C_Total
FROM <your_table> A
GROUP BY date
ORDER BY date
Output is-
date C_Total
01-01-2019 40
02-01-2019 60
03-01-2019 100
I suggest to use a window function, like this:
select date, sum(amount) over( order by date)
from table

How to get last quarterly and last half yearly average of balance for each month in hive?

I have a table with column cust_id, year_, month_, monthly_txn, monthly_bal. I need
to calculate the previous three month and previous six month avg(monthly_txn) and variance(monthly_bal) for each month. I have a query which returns avg and variance for last three and six month only for last month not for each month. I am not good in analytical function in Hive.
SELECT cust_id, avg(monthly_txn)y,variance(monthly_bal)x, FROM (
SELECT cust_id, monthly_txn,monthly_bal,
row_number() over (partition by cust_id order by year_,month_ desc) r
from mytable) b WHERE r <= 3 GROUP BY cust_id
But I want something like below.
input:
cust_id year_ month_ monthly_txn monthly_bal
1 2018 1 456 8979289
1 2018 2 675 4567
1 2018 3 645 4890
1 2017 1 342 44522
1 2017 2 378 9898900
1 2017 2 456 234492358
1 2017 4 3535 789
1 2017 5 456 345
1 2017 6 598 334
expecting output:
suppose for txn the quaterly and half yearly txn will be like this same for variance also
cust_id year_ month_ monthly_txn monthly_bal q_avg_txn h_avg_txn
1 2018 1 456 8979289 avg(456,598,4561) avg(456,598,4561,3535,4536,378)
1 2018 2 675 4567 avg(675,456,598) avg(675,456,3535,4561,598,4536)
1 2018 3 645 4890 avg(645,675,645) avg(645,675,645,3535,4561,598)
1 2017 1 342 44522 avg(342) avg(342)
1 2017 2 378 9898900 avg(378,342) avg(378,342)
1 2017 3 4536 234492358 avg(4536,372,342) avg(4536,378,342)
1 2017 4 3535 789 avg(3535,4536,378) avg(3535,4536,378,342)
1 2017 5 4561 345 avg(4561,3535,4536) avg(4561,3535,4536,342,378)
1 2017 6 598 334 avg(598,4561,3535) avg(598,4561,3535,4536,342,378)
use unbounded preceding analytic functions (/* to get the quarterly and half years values) and then use the subquery to get results.
What is ROWS UNBOUNDED PRECEDING used for in Teradata?
If you have data for every month of interest (i.e., no gaps), then this should work:
select t.*,
avg(monthly_bal) over (partition by cust_id
order by year_, month_
rows between 2 preceding and current row
) as avg_3,
avg(monthly_bal) over (partition by cust_id
order by year_, month_
rows between 5 preceding and current row
) as avg_6,
variance(monthly_bal) over (partition by cust_id
order by year_, month_
rows between 2 preceding and current row
) as variance_3,
variance(monthly_bal) over (partition by cust_id
order by year_, month_
rows between 5 preceding and current row
) as variance_6
from mytable t;

SUM Based Off A Criteria

How can I SUM "Orders" when there is a value for "Spend" and also the NULL rows that comes after it going from oldest to newest?
Current Output:
Date | Product | Spend | Orders
------------------------------------------------
2017-09-18 Product A NULL 7
2017-09-11 Product A NULL 7
2017-09-04 Product A 1000.00 16
2017-08-28 Product A NULL 7
2017-08-21 Product A 2000.00 35
2017-08-14 Product A 1000.00 20
2017-08-07 Product A NULL 3
2017-07-31 Product A NULL 3
2017-07-24 Product A 1000.00 14
Desired Output:
Date | Product | Spend | Orders | SUMMED Orders
---------------------------------------------------------------
2017-09-18 Product A NULL 7 NULL
2017-09-11 Product A NULL 7 NULL
2017-09-04 Product A 1000.00 16 30 (16 + 7 + 7)
2017-08-28 Product A NULL 7 NULL
2017-08-21 Product A 2000.00 35 42 (35 + 7)
2017-08-14 Product A 1000.00 20 20 (20)
2017-08-07 Product A NULL 3 NULL
2017-07-31 Product A NULL 3 NULL
2017-07-24 Product A 1000.00 14 20 (14 + 3 + 3)
I wrote the math expression in the SUMMED Orders column to show how I came up with the new total.
Thank you.
You can assign a group to the rows by counting the number of non-null rows that are older. You can then use this group to calculate the sum:
select t.*,
sum(orders) over (partition by product, grp) as summed_orders
from (select t.*,
sum( (spend is not null)::int ) over (partition by product order by date asc) as grp
from t
) t;
This doesn't remove the first row. I'm not sure what the logic is for removing that.
select "date", product, spend, orders, sum(orders) over (order by "date") rt
from t1
order by "date" desc , spend nulls first;