web-dev-qa-db-fra.com

SQL: Grouper par valeur minimale dans un champ lors de la sélection de lignes distinctes

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

id | record_date | other_cols
18 | 2011-04-03  | x
18 | 2012-05-19  | y
18 | 2012-08-09  | z
19 | 2009-06-01  | a
19 | 2011-04-03  | b
19 | 2011-10-25  | c
19 | 2012-08-09  | d

Pour chaque identifiant, je souhaite sélectionner la ligne contenant la date_enregistrement minimale. Donc j'aurais:

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

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

id | record_date | other_cols
18 | 2011-04-03  | x
19 | 2011-04-03  | b
19 | 2009-06-01  | a
46
user2765924

Que diriez-vous de quelque chose comme

SELECT mt.*,     
FROM MyTable mt INNER JOIN
    (
        SELECT ID, MIN(Record_Date) MinDate
        FROM MyTable
        GROUP BY ID
    ) t ON mt.ID = t.ID AND mt.Record_Date = t.MinDate

Cela obtient la date minimale par ID, puis les valeurs en fonction de ces valeurs. Les doublons ne sont possibles que s'il existe des dates d'enregistrement minimales en double pour le même ID.

65
Adriaan Stander

Je pourrais obtenir votre résultat attendu simplement en faisant ceci dans mysql :

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

Est-ce que ça marche pour toi?

10
Math

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 de la table products et renvoie les produits dont les prix unitaires correspondent au prix le plus bas de chaque catégorie renvoyé par la sous-requête corrélée.

6
DIMI

La requête ci-dessous prend la première date pour chaque ordre de travail (dans un tableau montrant toutes les modifications d'état):

SELECT
    WORKORDERNUM,
    MIN(DATE)
FROM
    WORKORDERS
WHERE
    DATE >= to_date('2015-01-01','YYYY-MM-DD')
GROUP BY
    WORKORDERNUM
0
SRVFan

Je voudrais ajouter quelques-unes des autres réponses ici, si vous n'avez pas besoin du premier mais du deuxième chiffre, par exemple, vous pouvez utiliser un nombre circulaire dans une sous-requête et baser votre résultat en conséquence.

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 de supprimer plusieurs colonnes de la sous-requête, ce qui peut être utile si deux dates_enregistrement ont des valeurs identiques. Vous pouvez également partitionner plusieurs colonnes si nécessaire en les délimitant par une virgule.

0
Reese De Wind

C'est une vieille question, mais cela peut être utile à quelqu'unEn ce qui me concerne, je ne peux pas utiliser une requête secondaire car j'ai une grande requête et j'ai besoin d'utiliser min () sur mon résultat, si j'utilise une requête secondaire, le besoin de la base de données ré-exécuter ma grande requête. J'utilise Mysql

select t.* 
    from (select m.*, @g := 0
        from MyTable m --here i have a big query
        order by id, record_date) t
    where (1 = case when @g = 0 or @g <> id then 1 else  0 end )
          and (@g := id) IS NOT NULL

Fondamentalement, j'ai ordonné le résultat, puis une variable afin de n'obtenir que le premier enregistrement de chaque groupe.

0