web-dev-qa-db-fra.com

En SQL, comment sélectionner les 2 premières lignes de chaque groupe

J'ai une table comme suit:

NAME    SCORE
-----------------
willy       1
willy       2
willy       3
zoe         4
zoe         5
zoe         6

Voici le échantillon

La fonction d'agrégation pour group by me permet seulement d'obtenir le score le plus élevé pour chaque name. J'aimerais effectuer une requête pour obtenir le score le plus élevé pour chaque name, comment dois-je procéder?

Ma sortie attendue est 

NAME    SCORE
-----------------
willy       2
willy       3
zoe         5
zoe         6
13
waitingkuo
SELECT *
FROM   test s
WHERE 
        (
            SELECT  COUNT(*) 
            FROM    test  f
            WHERE f.name = s.name AND 
                  f.score >= s.score
        ) <= 2
19
John Woo

Dans MySQL, vous pouvez utiliser des variables définies par l'utilisateur pour obtenir un numéro de ligne dans chaque groupe:

select name, score
from
(
  SELECT name,
    score,
    (@row:=if(@prev=name, @row +1, if(@prev:= name, 1, 1))) rn
  FROM test123 t
  CROSS JOIN (select @row:=0, @prev:=null) c
  order by name, score desc 
) src
where rn <= 2
order by name, score;

Voir Démo

10
Taryn

Si cela ne vous dérange pas d'avoir une colonne supplémentaire, vous pouvez utiliser le code suivant:

SELECT Name, Score, rank() over(partition by Name, order by Score DESC) as rank
From Table
Having rank < 3;

La fonction Rank fournit un classement pour chaque partition. Dans votre cas, il s'agit du nom

2
Avinash Shastri

Vous pouvez faire quelque chose comme ça:

SET @num :=0, @name :='';   
SELECT name, score,
    @num := IF( @name= name, @num +1, 1 ) AS row_number,
    @name := name AS dummy
FROM test
GROUP BY name, score
HAVING row_number <=2
0
user2674659
SELECT * FROM (   
    SELECT  VD.`cat_id` ,  
       @cat_count := IF( (@cat_id = VD.`cat_id`), @cat_count + 1, 1 ) AS 'DUMMY1', 
       @cat_id := VD.`cat_id` AS 'DUMMY2',
       @cat_count AS 'CAT_COUNT'   
     FROM videos VD   
     INNER JOIN categories CT ON CT.`cat_id` = VD.`cat_id`  
       ,(SELECT @cat_count :=1, @cat_id :=-1) AS CID  
     ORDER BY VD.`cat_id` ASC ) AS `CAT_DETAILS`
     WHERE `CAT_COUNT` < 4

------- STEP FOLLOW ----------  
1 . select * from ( 'FILTER_DATA_HERE' ) WHERE 'COLUMN_COUNT_CONDITION_HERE' 
2.  'FILTER_DATA_HERE'   
    1. pass 2 variable @cat_count=1 and  @cat_id = -1  
    2.  If (@cat_id "match" column_cat_id value)  
        Then  @cat_count = @cat_count + 1    
        ELSE @cat_count = 1      
    3. SET @cat_id = column_cat_id    

 3. 'COLUMN_COUNT_CONDITION_HERE'   
    1. count_column < count_number    

4. ' EXTRA THING '
   1. If you want to execute more than one statement inside " if stmt "
   2. IF(condition, stmt1 , stmt2 )
      1. stmt1 :- CONCAT(exp1, exp2, exp3) 
      2. stmt2 :- CONCAT(exp1, exp2, exp3) 
   3. Final "If" Stmt LIKE 
      1. IF ( condition , CONCAT(exp1, exp2, exp3) , CONCAT(exp1, exp2, exp3) )    
0
Jhamman Sharma

Pour cela, vous pouvez faire ceci-

http://www.sqlfiddle.com/#!2/ee665/4

mais pour obtenir les 2 premières requêtes, vous devez utiliser un ID puis exécuter limite pour un ID tel que 0,2.

0
devilcrab