2013-09-22 14 views
11

ho capito che una query di database stava tornando risultati imprevisti fanno per il mio uso improprio di "ON DISTINCT" e "GROUP BY"PostgreSQL - "ON DISTINCT" e "GROUP BY" sintassi

Sto sperando che qualcuno possa mettimi dritto su questo La query reale è piuttosto complessa, quindi mi muto verso il basso:

Ho un/query interna tabella che consiste in un object_id e un timestamp:

CREATE TABLE test_select (object_id INT , event_timestamp timestamp); 
COPY test_select (object_id , event_timestamp) FROM stdin (DELIMITER '|'); 
1   | 2013-01-27 21:01:20 
1   | 2012-06-28 14:36:26 
1   | 2013-02-21 04:16:48 
2   | 2012-06-27 19:53:05 
2   | 2013-02-03 17:35:58 
3   | 2012-06-14 20:17:00 
3   | 2013-02-15 19:03:34 
4   | 2012-06-13 13:59:47 
4   | 2013-02-23 06:31:16 
5   | 2012-07-03 01:45:56 
5   | 2012-06-11 21:33:26 
\. 

sto cercando di selezionare una distinta ID, ordinato/deduplicati dal timestamp Chron rovescio

quindi i risultati dovrebbero essere [4, 1, 3, 2, 5]

Penso che questo fa quello che mi serve (sembra):

SELECT object_id 
FROM test_select 
GROUP BY object_id 
ORDER BY max(event_timestamp) DESC 
; 

A scopo di verifica/controllo, a volte desidero includere il campo Data/ora. Non riesco a capire come includere un altro campo con quella query.

Qualcuno può segnalare problemi evidenti nel mio sql sopra, o suggerimenti su come includere le informazioni di controllo?

risposta

14

Per essere in grado di selezionare tutte le colonne e non solo object_id e MAX(event_timestamp), è possibile utilizzare DISTINCT ON

SELECT DISTINCT ON (object_id) 
    object_id, event_timestamp ---, more columns 
FROM test_select 
ORDER BY object_id, event_timestamp DESC ; 

Se si desidera che i risultati in ordine di event_timestamp DESC e non da object_id, è necessario includere in una tabella derivata o un CTE:

SELECT * 
FROM 
    (SELECT DISTINCT ON (object_id) 
     object_id, event_timestamp ---, more columns 
    FROM test_select 
    ORDER BY object_id, event_timestamp DESC 
) AS t 
ORDER BY event_timestamp DESC ; 

In alternativa, è possibile utilizzare le funzioni delle finestre, come ROW_NUMBER():

WITH cte AS 
    (SELECT ROW_NUMBER() OVER (PARTITION BY object_id 
           ORDER BY event_timestamp DESC) 
      AS rn, 
      object_id, event_timestamp ---, more columns 
    FROM test_select 
) 
SELECT object_id, event_timestamp ---, more columns 
FROM cte 
WHERE rn = 1 
ORDER BY event_timestamp DESC ; 

o aggregata MAX() con OVER:

WITH cte AS 
    (SELECT MAX(event_timestamp) OVER (PARTITION BY object_id) 
      AS max_event_timestamp, 
      object_id, event_timestamp ---, more columns 
    FROM test_select 
) 
SELECT object_id, event_timestamp ---, more columns 
FROM cte 
WHERE event_timestamp = max_event_timestamp 
ORDER BY event_timestamp DESC ; 
+0

Grazie! Il tuo secondo esempio era la sintassi che stavo cercando di capire. Verificherò le altre query per le prestazioni più tardi e vedrò se posso usarle. Sto costruendo questa query generativamente sulla base dell'input dell'utente, e quel secondo esempio è "facilmente realizzabile". –

3

Non è probabilmente il modo migliore di trattare con questo, ma si può provare a utilizzare la funzione finestra:

SELECT DISTINCT object_id, MAX(event_timestamp) 
OVER (PARTITION BY object_id) 
FROM test_select ORDER BY max DESC; 

Da altra parte funziona così:

SELECT object_id, MAX(event_timestamp) as max_event_timestamp 
FROM test_select 
GROUP BY object_id 
ORDER BY max_event_timestamp DESC;