views:

497

answers:

4

Assume we have the following table:

Id   A    B
1    10   ABC
2    10   ABC
3    10   FFF
4    20   HHH

As result of a "group by A" expression I want to have the value of the B-Column that occurs most often:

select A, mostoften(B) from table group by A;

A    mostoften(B)
10   ABC
20   HHH

How do I achieve this in Oracle 10g?

Remark: in the case of a tie (when there are more than one value that occurs most often) it does not matter which value is selected.

+5  A: 
select A, B
from (
  select A, B, ROW_NUMBER() OVER (PARTITION BY A ORDER BY C_B DESC) as rn
  from (
     select A, COUNT (B) as C_B, B
     from table
     group by A, B
  ) count_table
) order_table
where rn = 1;

You want the Bs with the MAX of COUNT group by A, B.

Remus Rusanu
Yes he does need the max count. But for performance issues, it's quicker to ask the sql engine to get them all, order them by occurence and he only needs to pick the first item of the resulting set. So that's why I prefer LFSR Consulting' answer over yours and the other answers so far.
Silence
My original post was actual incorrect, fixed
Remus Rusanu
Great. Oracle is just not happy with the "as" before "count_table" and "order_table", but otherwise it is fine.
mr_georg
I removed the 'as's :) Not an Oracle guy myself...
Remus Rusanu
A: 

try this (works on SQL Server 2005):

declare @yourtable table (rowid int, a int,b char(3))
insert into @yourtable values (1,10,'ABC')
insert into @yourtable values (2,10,'ABC')
insert into @yourtable values (3,10,'FFF')
insert into @yourtable values (4,20,'HHH')

;WITH YourTableCTE AS
(
SELECT
    *, ROW_NUMBER() OVER(partition by A ORDER BY A ASC,CountOfB DESC) AS RowRank
    FROM (SELECT 
              A, B, COUNT(B) AS CountOfB
              FROM @yourtable
              GROUP BY A,B
          ) dt
)
SELECT
    A,B
    FROM YourTableCTE
    WHERE RowRank=1

EDIT without CTE...

SELECT
    A,B
    FROM (SELECT
              *, ROW_NUMBER() OVER(partition by A ORDER BY A ASC,CountOfB DESC) AS RowRank
              FROM (SELECT 
                        A, B, COUNT(B) AS CountOfB
                        FROM @yourtable
                        GROUP BY A,B
                    ) dt
         ) dt2



    WHERE RowRank=1
KM
Oracle 10g does not support CTE's.
Bill Karwin
@Bill: Oracle has supported the WITH syntax since 9i; they call it Subquery Factoring.
OMG Ponies
A: 

This problem can be clarified by creating a view for the count in each A & B group:

CREATE VIEW MyTableCounts AS
  SELECT A, B, COUNT(*) C
  FROM MyTable
  GROUP BY A, B;

Now we can do a query that finds the row c1 where the count is greatest. That is, no other row that has the same A has a greater count. Therefore if we try to find a row c2 with a greater count, no match is found.

SELECT c1.A, c1.B
FROM MyTableCounts c1
LEFT OUTER JOIN MyTableCounts c2
  ON (c1.A = c2.A AND (c1.C < c2.C OR (c1.C = c2.C AND c1.B < c2.B)))
WHERE c2.A IS NULL
ORDER BY c1.A;

To resolve tied counts (c1.C = c2.C), we use the value of B which we know is unique within a given group of A.

Bill Karwin
This solution should work in any brand of SQL database, including Oracle 10g.
Bill Karwin
Just use the with-syntax instead of a view, Oracle 9, 10 and 11 support the with syntax.
tuinstoel
A: 

Old school solution, it took me some time and some cursing :)

select a,b
from   ta ta1
group by a,b
having count(*) = (select max(count(*))
                   from   ta ta2
                   where  ta1.a = ta2.a
                   group by b)
tuinstoel