web-dev-qa-db-ja.com

PostgreSQLでカテゴリごとに最大日付グループでIDを選択するにはどうすればよいですか?

たとえば、カテゴリごとに最大日付グループでidを選択したい場合、結果は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

PostgreSQLでこれを行う方法を知っていますか?

70
user2412043

これは DISTINCT ON (標準DISTINCTのPostgres固有の拡張)の完璧なユースケースです:

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

降順の並べ替えに注意してください。列がNULLになる可能性がある場合は、NULLS LASTを追加できます。

DISTINCT ONは最も簡単で高速です。この関連する回答の詳細な説明:

大きなテーブルの場合、この代替アプローチを検討してください。

categoryごとのmany行のパフォーマンス最適化:

116

これを試してください:

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

このSQLFiddle を参照してください

19
hims056

別のアプローチは、first_valueウィンドウ関数を使用することです。 http://sqlfiddle.com/#!12/7a145/14

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

...しかし、適切なインデックスが存在する場合、彼の提案は通常、パフォーマンスが向上すると思われます。

3番目の解決策は次のとおりです。

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