回答

收藏

PostgreSQL -``令人震惊的ISTINCT ON''和``ROUP BY''语法

技术问答 技术问答 166 人阅读 | 0 人回复 | 2023-09-14

我意识到数据库查询返回了意外的结果,这是由于我不正确地使用了“ DISTINCT ON”和“ GROUP BY”/ W* F$ c  ^1 R! V6 ?$ @2 L
我希望有人能使我对此有所了解。实际的查询非常复杂,因此我将其简化:
+ h6 }& O% U4 v, s: w- M: C& X% C我有一个由object_id和时间戳组成的表/内部查询:/ ^0 f" o  z1 u( N/ u5 Q4 z# ^
CREATE TABLE test_select ( object_id INT , event_timestamp timestamp );- d+ x- P$ V4 d* ~9 G! a' c" \
COPY test_select (object_id , event_timestamp) FROM stdin (DELIMITER '|');
" P% Z8 z1 K1 S4 ~$ p  w: I1           | 2013-01-27 21:01:20
6 ^- e. }' f+ S* W2 }8 i0 ~% X1           | 2012-06-28 14:36:26) E: y) F. {  z7 p! A- f4 z+ Y
1           | 2013-02-21 04:16:48
# r' o2 q. V# O1 l& e: P2 g* Q2           | 2012-06-27 19:53:052 w  q1 z! _* [
2           | 2013-02-03 17:35:586 X, Q3 Q( P" t+ `7 l
3           | 2012-06-14 20:17:00
) e$ G3 `: P! o" v& R: x3           | 2013-02-15 19:03:348 [2 }) V+ e  ^7 J' y: }0 k+ e
4           | 2012-06-13 13:59:47
% U$ N+ \7 u( b% c7 O8 _0 d4           | 2013-02-23 06:31:16, B. k1 f* X6 o
5           | 2012-07-03 01:45:56
5 `4 c: H, r& a! D5           | 2012-06-11 21:33:26! ?2 Y" @$ w; n
\.4 ?" i% a! W* d  X3 O$ j. ^
我正在尝试选择一个不同的ID,按反向计时的时间戳排序/去重复
5 T  z* J* H2 }0 E所以结果应该是[4,1,3,2,5]' }8 L# l6 |+ m# W+ L' C9 R
我认为这可以满足我的需求(似乎):+ d1 M3 s3 w5 I- C0 a
SELECT object_id  ! `; H6 G% b5 M3 d( r) }
FROM test_select
- V, n$ Y& K( w2 x! ?) N; C9 d+ iGROUP BY object_id . X; `0 W3 g, c% s8 J, b' k7 l
ORDER BY max(event_timestamp) DESC
4 [$ }- M& h: t; T* O  m# k;
7 C9 |0 C" M2 X2 b出于测试/审核的目的,有时我想包括timestamp字段。我似乎无法弄清楚如何在该查询中包含另一个字段。
/ s5 o; L" P! H, j任何人都可以指出以上我的sql中明显的问题,或有关如何包括审核信息的建议吗?- u$ O4 I) x( e+ E: |/ i
                . A; p/ V1 E: Z( F
解决方案:
* m+ B, |0 Z; G& a0 M) {- r               
& N5 \/ s3 C6 Y+ ?- F
4 _) \+ ?$ w' I$ `; u7 U% Z  p% A- @
                为了能够选择所有列,而不仅是object_id和MAX(event_timestamp),您可以使用DISTINCT ON3 E/ s; _7 B8 @2 p( _3 @$ _
SELECT DISTINCT ON (object_id)
1 L+ }" J, ?( W! g. z* j7 e  B    object_id, event_timestamp    ---, more columns* @0 |" {2 o3 S7 q" a& o2 x
FROM test_select
2 e3 r+ Z0 x; P% B4 F/ rORDER BY object_id, event_timestamp DESC ;
; W9 `. q8 p  P0 V: I3 D如果希望结果按event_timestamp DESC而不是按进行排序object_id,则需要将其包括在派生表或CTE中:8 G" j& W" u, L9 ]3 b
SELECT *
: A" Q# W$ U4 N% {# l% [; pFROM
' h6 D7 z4 Z  e0 m  ( SELECT DISTINCT ON (object_id)
+ E; R8 ~6 t) ^7 _( V        object_id, event_timestamp    ---, more columns  v" D# B/ ?0 I7 D2 l6 b8 o
    FROM test_select & g; d( n8 J2 R, d4 c  H
    ORDER BY object_id, event_timestamp DESC $ p; r2 |8 k1 D3 E0 \% Y' d
  ) AS t  {8 W: `2 T# X- H
ORDER BY event_timestamp DESC ;
# c7 B( X, L# Y7 x6 J% e( c+ d, n; A/ }另外,您可以使用窗口功能,例如ROW_NUMBER():
6 Q  K% @0 x9 }2 a4 }1 uWITH cte AS4 _8 }# ?$ `" L5 h# Q
  ( SELECT ROW_NUMBER() OVER (PARTITION BY object_id & Y/ R9 Y& y, Y5 n' U, [2 M
                              ORDER BY event_timestamp DESC) 5 d, Y; c. N" G# Y+ O
             AS rn,
6 X9 Y2 `/ b$ B" V' `  d: u3 w% s           object_id, event_timestamp    ---, more columns
, L/ I( {( E$ B( s8 t2 T0 y    FROM test_select * a- V4 ]  ?5 \
  )2 h9 U% g/ F8 Q0 K' ~; x$ w
SELECT object_id, event_timestamp    ---, more columns' g+ Y' ?. T; G8 |2 P5 d
FROM cte
0 K. P2 a0 Q9 m4 sWHERE rn = 1
! G. }' R2 o" x4 PORDER BY event_timestamp DESC ;6 `4 K0 g$ [; y# a4 W
或MAX()与OVER:+ `* V8 r: e: A9 L3 E  \+ V
WITH cte AS
) h# h: ?' D. Q' m& {/ P! ^  o  ( SELECT MAX(event_timestamp) OVER (PARTITION BY object_id)
+ G, C& {$ t& |" @) Q             AS max_event_timestamp,
* e9 l% r0 f) T, Y  r# h& l           object_id, event_timestamp    ---, more columns
' @, X* [1 O! E, O* v% [    FROM test_select
( C+ P- P# c5 v; I3 {6 L. j5 T' g  )
. M  O2 H- D5 N  VSELECT object_id, event_timestamp    ---, more columns
2 w, P# l" D3 F! tFROM cte
6 H! ~, Q8 r# ~) CWHERE event_timestamp = max_event_timestamp, e6 ?$ t( q# a4 S% ^  n
ORDER BY event_timestamp DESC ;
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则