web-dev-qa-db-fra.com

Comment sélectionner id avec max groupe de dates par catégorie dans PostgreSQL?

Par exemple, je voudrais sélectionner id avec groupe de dates maximum par catégorie, le résultat est le suivant: 7, 2, 6

id  category  date
1   a         2013-01-01
2   b         2013-01-03
3   c         2013-01-02
4   a         2013-01-02
5   b         2013-01-02
6   c         2013-01-03
7   a         2013-01-03
8   b         2013-01-01
9   c         2013-01-01

Puis-je savoir comment faire cela dans PostgreSQL?

70
user2412043

C'est un cas d'utilisation parfait pour DISTINCT ON (extension spécifique à la norme DISTINCT de Postgres):

SELECT DISTINCT ON (category)
       id  -- , category, date -- add any other column (expression) from the same row
FROM   tbl
ORDER  BY category, "date" DESC;

Attention avec l'ordre de tri décroissant. Si la colonne peut être NULL, vous pouvez ajouter NULLS LAST:

DISTINCT ON est simple et rapide. Explication détaillée dans cette réponse associée:

Pour les grandes tables, considérez cette approche alternative:

Optimisation des performances pour plusieurs lignes par category:

116

Essaye celui-là:

SELECT t1.* FROM Table1 t1
JOIN 
(
   SELECT category, MAX(date) AS MAXDATE
   FROM Table1
   GROUP BY category
) t2
ON T1.category = t2.category
AND t1.date = t2.MAXDATE

Voir this SQLFiddle

19
hims056

Une autre approche consiste à utiliser le first_value fonction de fenêtre: http://sqlfiddle.com/#!12/7a145/14

SELECT DISTINCT
  first_value("id") OVER (PARTITION BY "category" ORDER BY "date" DESC) 
FROM Table1
ORDER BY 1;

... bien que je soupçonne que la suggestion de hims056 donnera généralement de meilleurs résultats lorsque des index appropriés sont présents.

Une troisième solution est:

SELECT
  id
FROM (
  SELECT
    id,
    row_number() OVER (PARTITION BY "category" ORDER BY "date" DESC) AS rownum
  FROM Table1
) x
WHERE rownum = 1;
12
Craig Ringer