Reputation: 2772
My question is to find all those customers who have made the minimum and maximum no of orders.
what i could come up with is this :
select customer_id , count(order_id) as num
from bab_customer right outer join bab_order_details using(customer_id)
group by customer_id
having count(order_id) >=
all(select count(order_id)
from bab_customer right outer join bab_order_details using(customer_id)
group by customer_id)
or count(order_id) <=
all(select count(order_id)
from bab_customer right outer join bab_order_details using(customer_id)
group by customer_id);
it gives me the correct output , but i have to do the same join 3 times. is there some better way to do this ?
Upvotes: 0
Views: 660
Reputation:
If I absolutely felt this must be a single query, I'd probably just use a union all
.
(
select
customer_id,
count(*) as num
from bab_customer right outer join bab_order_details using(customer_id)
group by customer_id
order by num desc limit 1
)
union all
(
select
customer_id,
count(*) as num
from bab_customer right outer join bab_order_details using(customer_id)
group by customer_id
order by num asc limit 1
)
Originally, I'd been thinking this would perform better due to avoiding joins on intermediate values. However, I'm not seeing any performance gain here. (If it was faster, then limit could be raised to some arbitrary number and the application could trim out a few extra values without losing much of the increased performance)
But, no dice.
Upvotes: 0
Reputation: 33945
Is this better? I don't know...
SELECT x.*
FROM
( SELECT customer_id
, COUNT(*) cnt
FROM orders
GROUP
BY customer_id
) x
JOIN
( SELECT MIN(cnt) min_cnt
, MAX(cnt) max_cnt
FROM
( SELECT customer_id
, COUNT(*) cnt
FROM orders
GROUP
BY customer_id
) n
) y
ON y.min_cnt = x.cnt
OR y.max_cnt = x.cnt;
Upvotes: 2
Reputation: 1830
I realised, that you cannot run it in a single query without calling same subqueries several times. As you refer min(numOrders) and max(numOrders) you have to store numOrders as a temporal table or to calculate it twice. Most likely the DBMS will cache your requests if they are identical, so you should not worry about wasting resources.
So your query must be a bit rewrited and is good enough. My variant is
select customer_id , count(order_id) as num
from customers right outer join orders using(customer_id)
group by customer_id
having
num = (SELECT min(num) FROM (select count(order_id) as num
from customers right outer join orders using(customer_id)
group by customer_id) numOrders)
or
num = (SELECT max(num) FROM (select count(order_id) as num
from customers right outer join orders using(customer_id)
group by customer_id) numOrders)
You can check it working with this sqlfiddle
Upvotes: 1