简体   繁体   中英

SQL | How to sum over partition group of 3 items?

I'm trying to get the percent of a day's revenue for top 3 product categories but struggling with the percentage. I have already the revenue per product ranked 1 to 3 but cant wrap my head on how to get the percentage.

Any pointers will be appreciated.

SELECT * FROM (
SELECT   date, 
         category_name,
         revenue,
         row_number() OVER(PARTITION BY DATE(date) ORDER BY revenue DESC) AS category_rank,
         (revenue / (select sum(revenue) from a group by 1)) * 100 percentage AS percentage_of_daily_total -- this is the wrong one 

  FROM (
    SELECT DATE(orders.order_timestamp) AS date,
           products.product_cat AS category_name,
           ROUND(SUM(payments.payment)) AS revenue
    FROM table1.orders orders
    JOIN table1.t_payments payments ON orders.order_id = payments.order_id
    JOIN table1.t_items items ON orders.order_id = items.order_id
    JOIN table1.t_products products ON items.product_id = products.product_id
    GROUP BY 1 ,2) a) b
WHERE category_rank <= 3;

Sample data is as follow: date, category_name, revenue, category_rank

2016-10-05  jeans       20  1
2016-10-05  shirts      15  2
2016-10-05  shoes       10  3
2016-10-06  skirts      50  1
2016-10-06  sports_wear 30  2
2016-10-06  accesories  10  3

Desired outcome:date, category_name, revenue, category_rank, percentage_of_daily_total

2016-10-05  jeans       30  1  50
2016-10-05  shirts      20  2  33
2016-10-05  shoes       10  3  17
2016-10-06  skirts      20  1  50 
2016-10-06  sports_wear 16  2  40
2016-10-06  accessories 4   3  10

Use CTE s

WITH a AS (
    SELECT DATE(orders.order_timestamp) AS date,
           products.product_cat AS category_name,
           ROUND(SUM(payments.payment)) AS revenue
    FROM table1.orders orders
    JOIN table1.t_payments payments ON orders.order_id = payments.order_id
    JOIN table1.t_items items ON orders.order_id = items.order_id
    JOIN table1.t_products products ON items.product_id = products.product_id
    GROUP BY 1 ,2
)

SELECT * FROM (
SELECT   a.date, 
         a.category_name,
         a.revenue,
         row_number() OVER(PARTITION BY DATE(a.date) ORDER BY a.revenue DESC) AS category_rank,
         (a.revenue / b.revenue_sum) * 100 percentage AS percentage_of_daily_total
  FROM a
  JOIN (SELECT date, sum(revenue) AS revenue_sum FROM a GROUP BY 1) AS b
  ON a.date = b.date)
WHERE category_rank <= 3;

Your original query is very close. Calculate the percent in the OUTERMOST sql. So drop your percentage calc and then in the outer Select:

Select *, 100*revenue/(sum(revenue) Over (Partition by Date)) as percentage_of_daily_total

Remember that by the time you get to calculating the windowing functions the Where clause has already been executed and you're down to 3 records per day so any total will only be based on the top 3.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM