2009-09-01 4 views
1

Supposons que nous avons le tableau suivant:En SQL dans une expression "group by": comment obtenir la chaîne qui se produit le plus souvent dans un groupe?

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

Comme résultat d'un « groupe par une » expression je veux avoir la valeur de la colonne B qui se produit le plus souvent:

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

A mostoften(B) 
10 ABC 
20 HHH 

Comment est-ce que je réalise cela dans Oracle 10g?

Remarque: En cas d'égalité (lorsque plusieurs valeurs surviennent le plus souvent), peu importe la valeur sélectionnée.

Répondre

5
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; 

Vous voulez les hôtes avec MAX du groupe COUNT par A, B.

+0

Oui, il a besoin du nombre max. Mais pour les problèmes de performances, il est plus rapide de demander au moteur sql de les récupérer tous, de les trier par occurrence et de ne sélectionner que le premier élément de l'ensemble résultant. C'est pourquoi je préfère la réponse de LFSR Consulting à la vôtre et aux autres réponses jusqu'à présent. –

+0

Mon message original était réel incorrect, fixe –

+0

Great. Oracle n'est tout simplement pas satisfait du "as" avant "count_table" et "order_table", mais sinon ça va. –

0

essayez ceci (fonctionne sur 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 sans 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 
+0

Oracle 10g ne supporte pas les CTE. –

+1

@Bill: Oracle supporte la syntaxe WITH depuis 9i; ils l'appellent sous-requête factorisation. –

0

Ce problème peut être clarifié en créant une vue pour le comptage dans chaque A & groupe B:

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

Maintenant, nous pouvons faire une requête qui trouve la ligne c1 où le compte est le plus grand. Autrement dit, aucune autre ligne qui a le même A n'a un plus grand nombre. Par conséquent, si nous essayons de trouver une ligne c2 avec un plus grand nombre, aucune correspondance n'est trouvée.

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; 

Pour résoudre compte à égalité (c1.C = c2.C), nous utilisons la valeur de B que nous connaissons est unique au sein d'un groupe de A donné.

+0

Cette solution devrait fonctionner dans n'importe quelle marque de base de données SQL, y compris Oracle 10g. –

+1

Utilisez simplement la syntaxe with au lieu d'une vue, Oracle 9, 10 et 11 supportent la syntaxe with. – tuinstoel

1

ancienne solution de l'école, il m'a fallu un peu de temps et quelques jurons :)

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) 
Questions connexes