Reputation: 105
I need to perform a query to get the candies that are most liked by kids and here's what I've got:
SELECT COUNT(*) as counts,candies.name
FROM candies
INNER JOIN kid_candy ON kid_candy.candy_id = candies.id
INNER JOIN kids ON kids.id = kid_candy.kid_id
GROUP BY candies.name
which would return:
counts | name
--------+---------
3 | snowbear
3 | whiterabbit
2 | lollipop
All I want to see would be just
counts | name
--------+---------
3 | snowbear
3 | whiterabbit
So what should my query be?
Upvotes: 2
Views: 157
Reputation: 656882
Assuming a classical n:m relationship between kids and candies like detailed here:
You should provide such details in your question.
SELECT c.id, kc.counts, c.name
FROM (
SELECT candy_id AS id, count(*) AS counts
, rank() OVER (ORDER BY count(*) DESC) AS rnk
FROM kid_candy
GROUP BY 1
) kc
JOIN candies c USING (id)
WHERE kc.rnk = 1;
This should be considerably faster than a query with two CTEs and needless joins.
It is potentially wrong (and more expensive) to group by candies.name
. The name might not be unique. Use the primary key column for that, which is probably candies.id
Assuming referential integrity we do not need to join to the table kids
at all.
Since we need to inspect the whole table, it is faster to aggregate first and join to candies to get the name
later.
You can run a window function over an aggregate function:
Upvotes: 1
Reputation: 579
Do a sub select
Select max(counts)
(select COUNT(*) as counts,candies.name from candies
INNER JOIN kid_candy ON kid_candy.candy_id = candies.id
INNER JOIN kids ON kids.id = kid_candy.kid_id
GROUP BY candies.name)
Upvotes: 0
Reputation: 28403
Try this
SELECT * FROM
(
SELECT COUNT(*) AS Counts,candies.name FROM candies
INNER JOIN kid_candy ON kid_candy.candy_id = candies.id
INNER JOIN kids ON kids.id = kid_candy.kid_id
GROUP BY candies.name
) T1 JOIN
SELECT MAX(counts) MaxCount FROM
(
SELECT COUNT(*) AS Counts,candies.name FROM candies
INNER JOIN kid_candy ON kid_candy.candy_id = candies.id
INNER JOIN kids ON kids.id = kid_candy.kid_id
GROUP BY candies.name
) T1 ON T1.counts =T2.MaxCount
Upvotes: 0
Reputation: 876
So, first lets get the counts per candy name (tmp_table
), then get the max count of all candies (max_cnt
) and finally put it all together and get the candies from tmp_table
which have a count equal to max(counts)
from max_cnt
table...
with tmp_table AS (
select COUNT(*) as counts,candies.name as c_name
from candies
INNER JOIN kid_candy ON kid_candy.candy_id = candies.id
INNER JOIN kids ON kids.id = kid_candy.kid_id
GROUP BY candies.name
),
max_cnt AS (
SELECT max(counts) as max_count from tmp_table
)
SELECT counts, c_name as candies
FROM tmp_table
JOIN max_cnt on max_count = counts
Upvotes: 3