Home > other >  Aggregate and count conditionally but return all lines
Aggregate and count conditionally but return all lines

Time:12-03

My table structure is like this:

 ---------- ------------ --------------- 
| id       | manager_id | restaurant_id |
 ---------- ------------ --------------- 
| 1        | 1          | 1001          |
| 2        | 1          | 1002          | 
| 3        | 2          | 1003          |
| 4        | 2          | 1004          |
| 5        | 2          | 1005          |
| 6        | 3          | 1006          |
 ---------- ------------ --------------- 

I want to retrieve all the restaurant_id aggregated per manager_id, Additionally, I also need to filter per manager's count(restaurant_id): returning only restaurants of managers that have more than one restaurant, and less than 3.

Edit: this is an oversimplified version of the real data, my actual use case must cover more than one to 5 (included).

So that in the end, the result would be

 --------------- ------------ 
| restaurant_id | manager_id | 
 --------------- ------------ 
| 1001          | 1          |
| 1002          | 1          |
 --------------- ------------ 

I tried something similar to:

SELECT 
  restaurant_id, 
  manager_id,
  COUNT(*) AS restaurant_count
FROM 
  Manager_Restaurant
GROUP BY 
  manager_id
HAVING 
  restaurant_count > 1 and 
  restaurant_count < 3;

But this return only one line per manager because of the grouping and I want all the restaurants.

CodePudding user response:

You can make use of a windowed count here. More than 1 and less than 3 is 2:

select restaurant_id, manager_id
from (
  select *, Count(*) over(partition by manager_id) cnt
  from t
)t
where cnt = 2;

CodePudding user response:

Window (aka analytic) functions were designed with just such a case in mind.

You can use a window function to assign to each row the counts for a particular grouping, then select the rows having the required counts. Here is an example:

create table manager_restaurant (id int,manager_id int,restaurant_id int);
insert into manager_restaurant 
  values (1,1,1001),(2,1,1002),(3,2,1003),(4,2,1004),(5,2,1005),(6,3,1006);


select manager_id,restaurant_id from (
  select *,
    count(1) over (partition by manager_id) as n 
  from 
    manager_restaurant
  )x 
 where 
   n>1 and n<3 ;
manager_id restaurant_id
1 1001
1 1002
  • Related