2013-09-22 34 views
11

tôi nhận ra rằng một truy vấn cơ sở dữ liệu được trả về kết quả bất ngờ làm gì để sử dụng không đúng của tôi về "ON DISTINCT" và "GROUP BY"PostgreSQL - "ON DISTINCT" và "GROUP BY" cú pháp

Tôi hy vọng ai đó có thể đặt tôi thẳng vào điều này. Truy vấn thực tế là khá phức tạp, vì vậy tôi sẽ câm nó xuống:

Tôi có một bảng/truy vấn bên trong đó bao gồm một object_id và một dấu thời gian:

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 
\. 

Tôi đang cố gắng để lựa chọn một biệt ID, ra lệnh/loại bỏ trùng lặp bởi dấu thời gian trên Sử ký ngược

nên kết quả sẽ được [4, 1, 3, 2, 5]

tôi nghĩ rằng đây có phải những gì tôi cần (có vẻ như):

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

Đối với mục đích kiểm tra/kiểm tra, đôi khi tôi muốn bao gồm trường dấu thời gian. Tôi dường như không thể tìm ra cách bao gồm một trường khác với truy vấn đó.

Có ai có thể chỉ ra các vấn đề rõ ràng trong sql của tôi ở trên hoặc đề xuất về cách bao gồm thông tin kiểm tra?

Trả lời

14

Để có thể chọn tất cả các cột và không chỉ object_idMAX(event_timestamp), bạn có thể sử dụng DISTINCT ON

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

Nếu bạn muốn các kết quả theo yêu cầu của event_timestamp DESC và không phải bởi object_id, bạn cần phải bao gồm nó trong một bảng có nguồn gốc hoặc một 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 ; 

Ngoài ra, bạn có thể sử dụng chức năng cửa sổ, giống như 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 ; 

hoặc tổng hợp MAX() với 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

Cảm ơn! Ví dụ thứ hai của bạn là cú pháp tôi đã cố gắng hiểu. Tôi sẽ kiểm tra các truy vấn khác để thực hiện sau này và xem liệu tôi có thể sử dụng chúng hay không. Tôi đang xây dựng truy vấn này dựa trên đầu vào của người dùng và ví dụ thứ hai là "dễ dàng thực hiện được". –

3

Nó có lẽ không phải là cách tốt nhất để đối phó với điều này, nhưng bạn có thể thử sử dụng chức năng cửa sổ:

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

Từ Mặt khác nó hoạt động cũng như:

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