次の表test
を検討してください。
CREATE TABLE test(col1 int, col2 varchar, col3 date);
INSERT INTO test VALUES
(1,'abc','2015-09-10')
, (1,'abc','2015-09-11')
, (2,'xyz','2015-09-12')
, (2,'xyz','2015-09-13')
, (3,'tcs','2015-01-15')
, (3,'tcs','2015-01-18');
postgres=# select * from test;
col1 | col2 | col3
------+------+------------
1 | abc | 2015-09-10
1 | abc | 2015-09-11
2 | xyz | 2015-09-12
2 | xyz | 2015-09-13
3 | tcs | 2015-01-15
3 | tcs | 2015-01-18
返されたセットを日付descで並べ替えたい:
col1 | col2 | col3
------+------+------------
2 | xyz | 2015-09-13
1 | abc | 2015-09-11
3 | tcs | 2015-01-18
私がdistinct on
で何とか達成したこと:
select distinct on (col1) col1, col2, col3 from test order by col1, col3 desc;
col1 | col2 | col3
------+------+------------
1 | abc | 2015-09-11
2 | xyz | 2015-09-13
3 | tcs | 2015-01-18
having
で必要なものではありません:
select distinct on (col1) col1, col2, col3 from test group by col1, col2, col3 having col3 = max(col3)
col1 | col2 | col3
------+------+------------
1 | abc | 2015-09-10
2 | xyz | 2015-09-13
3 | tcs | 2015-01-18
_DISTINCT ON
_は引き続き使用できます。それを外部クエリにラップして、ニーズに合わせて並べ替えます。見る:
_SELECT *
FROM (
SELECT DISTINCT ON (col1)
col1, col2, col3
FROM test
ORDER BY col1, col3 DESC
) sub
ORDER BY col3 DESC, col2;
_
_col2
_が機能的に_col1
_に依存すると仮定すると、内部クエリの_DISTINCT ON
_および_ORDER BY
_では無視できます。しかし、意味のあるタイブレーカーとして、外側の_ORDER BY
_に追加しました。 _col2
_なしで_col1
_が一意でない場合は、_col1
_を追加することができます。
_col3
_が_NOT NULL
_として定義されていると仮定します。そうでない場合、_NULLS LAST
_を追加します。
_(col1)
_あたりfew行のみの場合、これは通常は最速のソリューション。見る:
db <> fiddle ここ
ウィンドウ関数row_number()
を持つサブクエリ(Véraceが提案したような)は有効な代替手段ですが、通常は低速です。私は 多くのテスト を実行しましたが、自分で試してください。 _DISTINCT ON
_(高速であると予想される場合は内部でハッシュアルゴリズムに切り替わる可能性があります)のように2回ソートする必要がありますが、内部クエリの後にすべての行を保持し、不要なコストを追加します。どちらの方法でも、内部クエリに_ORDER BY
_は必要ありません。
_SELECT col1, col2, col3
FROM (
SELECT col1, col2, col3
, row_number() OVER (PARTITION BY col1 ORDER BY col3 DESC) AS rn
FROM test
) sub
WHERE rn = 1
ORDER BY col3 DESC, col2;
_
また、CTEが必要ない場合は使用しないでください。通常はかなり高価です(ほとんどの場合これが修正されたPostgres 12まで)。
_col1
_あたりのmany行の場合、インデックス付けがはるかに重要になり、通常ははるかに高速な代替手段。見る:
余談ですが、OracleやSQL Serverとは異なり、PostgreSQLは ウィンドウ関数 に対して「分析関数」という用語を使用しません。 (これらの関数の「分析」とは何ですか?)
これは定番です greatest-n-per-group
問題があります。それらは頻繁に領域のホスト全体で発生し、 Analytic functions
(以下を参照)は学ぶ価値があります。
現在、これは通常、Analytic(別名Window)関数を使用することで解決されます。フィドル here
を参照してください。
このクエリを使用できます-
WITH cte AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS rn,
col1, col2, col3
FROM test
ORDER BY col3 DESC
)
SELECT * FROM cte
WHERE rn = 1
結果-
rn col1 col2 col3
1 2 xyz 2015-09-13
1 1 abc 2015-09-11
1 3 tcs 2015-01-18
分析関数は知っておく価値があります-それらは非常に強力であり、学習に費やしたあらゆる努力に対して何度も返済することがわかります。内部クエリを単独で実行します-実験、それが私が学んだ方法です。ところで、使用しているPostgreSQLのバージョンで質問にタグを付けることは常に価値があります!
これを行うより伝統的な方法は
SELECT x, y, mc FROM
(
SELECT col1 AS x, col2 AS y, MAX(col3) AS mc
FROM test
GROUP BY col1, col2
) AS tab
ORDER BY mc
同じ結果-フィドルでも。