Home > Back-end >  SQL: Get week range (week 1-2 or week 1, 2) for each week where item has the most sales out of items
SQL: Get week range (week 1-2 or week 1, 2) for each week where item has the most sales out of items

Time:04-28

Building off a general SQL question I already asked using online SQLite editor here, if I have the following table:

item week sales
item1 1 35
item2 1 25
item3 1 24
item1 2 35
item2 2 34
item1 3 24
item2 3 45
item1 4 44
item2 4 51
item1 5 1
item3 5 100

how would I get the output to be this:

item weeks total_sales
item1 1-2 70
item2 3-4 96
item3 5 100

In the table directly above, weeks 1-2 are assigned to item1 since the total sales for that time period were highest for item1. Same with weeks 3-4, assigned to item2 since that item's total sales were the highest for that time period.

Some code I have been working on is as follows:

SELECT item, 
    SUM(sales) OVER (
          PARTITION BY week order by item) AS total_sales
FROM TABLE1
GROUP BY item;

CASE was suggested to get the "range" for week the item sold the most out of all items, but this populates the items with the same week range. With case added, code is this:

SELECT item,
       CASE 
         WHEN week <= 2 THEN '1-2'
         WHEN week <= 4 THEN '3-4'
         WHEN week <= 5 THEN '5'
         ELSE '>5'
       END weeks,
       SUM(sales) OVER(partition by week order by item) as total_sales
FROM table1
GROUP BY item;

Here is a demo

The above code outputs something similar to:

item weeks total_sales
item1 1-2 70
item2 1-2 96
item3 1-2 100

which is wrong as only item1 was the top seller during weeks 1-2.

I really am not sure how one would get the week(s) for an item when it was the top seller. Again, item1 would have just "Week 1-2" populated once, item2 would have just "Week 3-4" populated once as those were their highest selling weeks.

Everything else I have done just fine. Any guidance or help is very much appreciated.

CodePudding user response:

I think if you just add a row_number() function to implement your business logic and then pick the rows where the row_number() = 1.

here is the fiddle https://www.db-fiddle.com/f/oWBDK3xTSgiCMaw7MS5XKm/0

and here is the fiddle with your demo data https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=62450660190d7f161f5790d188736260

with t as (
SELECT item,
       CASE 
         WHEN week <= 2 THEN '1-2'
         WHEN week <= 4 THEN '3-4'
         WHEN week <= 5 THEN '5'
         ELSE '>5'
       END weeks,
       SUM(sales) as total_sales
FROM table1
GROUP BY item, 
  CASE 
         WHEN week <= 2 THEN '1-2'
         WHEN week <= 4 THEN '3-4'
         WHEN week <= 5 THEN '5'
         ELSE '>5'
       END ),
  t2 as (
  select item, weeks, total_sales,
  row_number() over (partition by weeks order by total_sales desc) rn  from t)
  select * from t2 where rn = 1 order by weeks

CodePudding user response:

You need 2 levels of aggregation:

SELECT item, weeks, MAX(total_sales) total_sales
FROM (
  SELECT item,
         CASE 
           WHEN week <= 2 THEN '1-2'
           WHEN week <= 4 THEN '3-4'
           WHEN week <= 5 THEN '5'
           ELSE '>5'
         END weeks,
         SUM(sales) total_sales
  FROM table1
  GROUP BY item, weeks
)
GROUP BY item;

The outer query uses SQLite's feature of Bare columns in an aggregate query and returns the row with the max value of total_sales.

See the demo.

  • Related