99 votes

Grouper par valeur minimale dans un champ tout en sélectionnant des lignes distinctes

Voici ce que j'essaie de faire. Disons que j'ai ce tableau t :

key_id | id | record_date | other_cols
1      | 18 | 2011-04-03  | x
2      | 18 | 2012-05-19  | y
3      | 18 | 2012-08-09  | z
4      | 19 | 2009-06-01  | a
5      | 19 | 2011-04-03  | b
6      | 19 | 2011-10-25  | c
7      | 19 | 2012-08-09  | d

Pour chaque identifiant, je veux sélectionner la ligne contenant la date d'enregistrement minimale. J'obtiendrais donc

key_id | id | record_date | other_cols
1      | 18 | 2011-04-03  | x
4      | 19 | 2009-06-01  | a

Les seules solutions que j'ai vues à ce problème supposent que toutes les entrées record_date sont distinctes, mais ce n'est pas le cas dans mes données. L'utilisation d'une sous-requête et d'une jointure interne avec deux conditions me donnerait des lignes en double pour certains identifiants, ce que je ne veux pas :

key_id | id | record_date | other_cols
1      | 18 | 2011-04-03  | x
5      | 19 | 2011-04-03  | b
4      | 19 | 2009-06-01  | a

135voto

astander Points 83138

Pourquoi pas quelque chose comme :

SELECT mt.*     
FROM MyTable mt INNER JOIN
    (
        SELECT id, MIN(record_date) AS MinDate
        FROM MyTable
        GROUP BY id
    ) t ON mt.id = t.id AND mt.record_date = t.MinDate

Cette opération permet d'obtenir la date minimale par ID, puis les valeurs basées sur ces valeurs. Le seul cas où il y aurait des doublons est celui où il y aurait deux dates minimales d'enregistrement pour le même identifiant.

16voto

Math Points 1511

J'ai pu obtenir le résultat escompté en procédant de la manière suivante mysql :

 SELECT id, min(record_date), other_cols 
  FROM mytable
  GROUP BY id

Cela vous convient-il ?

10voto

DIMI Points 109

Pour obtenir le produit le moins cher dans chaque catégorie, vous utilisez la fonction MIN() dans une sous-requête corrélée comme suit :

    SELECT categoryid,
       productid,
       productName,
       unitprice 
    FROM products a WHERE unitprice = (
                SELECT MIN(unitprice)
                FROM products b
                WHERE b.categoryid = a.categoryid)

La requête externe analyse toutes les lignes du tableau des produits et renvoie les produits dont le prix unitaire correspond au prix le plus bas dans chaque catégorie renvoyée par la sous-requête corrélée.

4voto

Reese De Wind Points 146

J'aimerais ajouter à certaines des réponses données ici que si vous n'avez pas besoin de la premier mais disons le deuxième nombre par exemple, vous pouvez utiliser rownumber dans une sous-requête et baser votre ensemble de résultats sur cela.

SELECT * FROM
(
    SELECT
        ROW_NUM() OVER (PARTITION BY Id ORDER BY record_date, other_cols) as rownum,
        *
    FROM products P
) INNER
WHERE rownum = 2

Cela vous permet également d'ordonner plusieurs colonnes dans la sous-requête, ce qui peut s'avérer utile si deux records_dates ont des valeurs identiques. Vous pouvez également séparer plusieurs colonnes si nécessaire en les délimitant par une virgule

3voto

jeff Points 11

C'est tout simple :

select t2.id,t2.record_date,t2.other_cols 
from (select ROW_NUMBER() over(partition by id order by record_date)as rownum,id,record_date,other_cols from MyTable)t2 
where t2.rownum = 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