100 votes

Obtenir des enregistrements avec le <whatever> le plus petit/le plus grand par groupe

Comment obtenir des enregistrements avec le plus grand / plus petit par groupe?

L'ancien titre de cette question était "utilisation de rank (@Rank := @Rank + 1) dans une requête complexe avec des sous-requêtes - est-ce que ça marchera?" parce que je cherchais une solution utilisant des rangs, mais maintenant je vois que la solution proposée par Bill est bien meilleure.

Question originale :

Je cherche à composer une requête qui prendrait le dernier enregistrement de chaque groupe en fonction d'un ordre défini :

SET @Rank=0;

select s.*
from (select GroupId, max(Rank) AS MaxRank
      from (select GroupId, @Rank := @Rank + 1 AS Rank 
            from Table
            order by OrderField
            ) as t
      group by GroupId) as t 
  join (
      select *, @Rank := @Rank + 1 AS Rank
      from Table
      order by OrderField
      ) as s 
  on t.GroupId = s.GroupId and t.MaxRank = s.Rank
order by OrderField

L'expression @Rank := @Rank + 1 est normalement utilisée pour le rang, mais pour moi cela semble suspect quand elle est utilisée dans 2 sous-requêtes, mais initialisée une seule fois. Est-ce que cela fonctionnera de cette manière?

Et deuxièmement, est-ce que cela fonctionnera avec une seule sous-requête qui est évaluée plusieurs fois? Comme une sous-requête dans la clause where (ou having) (une autre façon d'écrire ce qui précède) :

SET @Rank=0;

select Table.*, @Rank := @Rank + 1 AS Rank
from Table
having Rank = (select max(Rank) AS MaxRank
              from (select GroupId, @Rank := @Rank + 1 AS Rank 
                    from Table as t0
                    order by OrderField
                    ) as t
              where t.GroupId = table.GroupId
             )
order by OrderField

Merci d'avance!

1voto

Rafi Points 530

Si vous souhaitez réaliser une logique plus sophistiquée que simplement le premier résultat, comme obtenir seulement le 2ème résultat ou le premier résultat avec une certaine contrainte:

select *
from (
    select
        [GroupId] , [columnName], OrderField,
        ROW_NUMBER() OVER(PARTITION BY [GroupId] ORDER BY OrderField DESC) AS row_number
    from Table_NAME(nolock)
    where [columnName]!='BadValue'
    ) a
where a.row_number = 1

0voto

Tom Williams Points 1

Ou vous pouvez utiliser order by et limit, c'est-à-dire :

SÉLECTIONNER * DE LA TABLE ORDER BY ORDERFIELD DESC LIMIT 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X