camohreally
camohreally

Reputation: 149

SQL: Find highest occurrence of a column value in a table?

I'm trying to find the most ordered menu item in a table by counting the occurrences of their item id. I've tried a few different things but I'm pretty lost. This produced the error:

"An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference."

However I think it puts into perspective what I'm trying to achieve:

SELECT count(itemCode) 
FROM OrderProcessing 
WHERE count(itemCode)=max(count(itemCode))

Upvotes: 6

Views: 14282

Answers (5)

TommCatt
TommCatt

Reputation: 5636

A where clause that contains aggregation results is called a having clause. However, you cannot nest aggregation functions: Max( Count( * )).

But you can layer them. The use of CTEs is good for this:

with
Data( ItemID )as(
    select 1 union all
    select 2 union all
    select 2 union all
    select 3 union all
    select 3 union all
    select 3
),
Sums( ItemID, TotalSold )as(
    select  ItemID, Count( * )
    from    Data
    group by ItemID
)
select  *
from    Sums
where   TotalSold =(
    select Max( TotalSold )
    from    Sums );

This will show all items with the most transactions. However, due to the question this query is purported to be answering, I should think that showing all ties would be the correct result. If Items X and Y both sold the most, to submit Item X as the answer, then by implication all other items, including Item Y, sold less. That is not a correct answer. I would discuss this more with your analyst or whomever is asking for this result.

Upvotes: 2

shA.t
shA.t

Reputation: 16968

I use this query to find items that have highest occurrence:

SELECT t.*
FROM OrderProcessing t
    JOIN
    (SELECT itemCode, ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) seq
    FROM OrderProcessing
    GROUP BY itemCode) dt
    ON t.itemCode= dt.itemCode
WHERE dt.seq = 1

And this query to find that count of highest occurrence:

SELECT MAX(cnt) 
FROM (SELECT COUNT(*) cnt 
      FROM OrderProcessing 
      GROUP BY itemCode) dt 

Upvotes: 2

Gordon Linoff
Gordon Linoff

Reputation: 1269913

If you want one row, I would suggest order by:

SELECT TOP 1 itemCode, count(itemCode)
FROM OrderProcessing
GROUP BY itemCode
ORDER BY count(itemCode);

If you want all items with the maximum count, use WITH TIES:

SELECT TOP 1 WITH TIES itemCode, count(itemCode)
FROM OrderProcessing
GROUP BY itemCode
ORDER BY count(itemCode);

If you want to be fancy, use window functions. Here is an example:

SELECT itemCode, cnt
FROM (SELECT itemCode, count(itemCode) as cnt,
             MAX(count(itemCode)) OVER () as maxcnt
      FROM OrderProcessing
      GROUP BY itemCode
     ) op
WHERE cnt = maxcnt;

Upvotes: 5

ASh
ASh

Reputation: 35680

I. modified version of original query (UPDATE after @DanGuzman comment about ties)

select all items with the same count as most wanted item:

SELECT itemCode , count(*) as MaxCount
FROM OrderProcessing
GROUP BY itemCode
HAVING count(*) = 
-- count of most wanted item
(select top 1 count(*) 
 from OrderProcessing 
 group by itemCode 
 order by count(*) desc)

II. the query to select one of most ordered items

SELECT top 1 itemCode --, count(*) as MaxCount  --optional
FROM OrderProcessing
GROUP BY itemCode
ORDER BY count(*) DESC

Upvotes: 8

Evaldas Buinauskas
Evaldas Buinauskas

Reputation: 14077

This is another way of doing that:

SELECT OP.itemCode
FROM (
    SELECT OP.itemCode, OP.TotalRows, MAX(TotalRows) OVER() AS MaxRows
    FROM (
        SELECT OP.itemCode, COUNT(*) AS TotalRows
        FROM dbo.OrderProcessing AS OP
        GROUP BY OP.itemCode
    ) AS OP
) AS OP
WHERE OP.TotalRows = OP.MaxRows;

It doesn't look very pretty, but it could result in better execution plan (sort is a really resource-hungry clause).

It also should return you results even if there's more than one Menu Item with same occurence.

Upvotes: 2

Related Questions