Làm thế nào để chọn id với nhóm ngày tối đa theo danh mục trong PostgreSQL?


89

Ví dụ: tôi muốn chọn id với nhóm ngày tối đa theo danh mục, kết quả là: 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

Tôi có thể biết cách thực hiện việc này trong PostgreSQL không?


4
Luôn luôn là khôn ngoan khi bao gồm phiên bản PostgreSQL của bạn.
Erwin Brandstetter

Câu trả lời:


142

Đây là một trường hợp sử dụng hoàn hảo cho DISTINCT ON(phần mở rộng cụ thể của Postgres của tiêu chuẩn DISTINCT):

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

Cẩn thận với thứ tự sắp xếp giảm dần. Nếu cột có thể là NULL, bạn có thể muốn thêm NULLS LAST:

DISTINCT ONlà đơn giản và nhanh chóng. Giải thích chi tiết trong câu trả lời liên quan này:

Đối với các bảng lớn, hãy xem xét cách tiếp cận thay thế này:

Tối ưu hóa hiệu suất cho nhiều hàng trên mỗi category:


Có vẻ tuyệt vời nhưng bạn có chắc chắn điều này được đảm bảo hoạt động mọi lúc không?
Atherion

@Tixel: Hoàn toàn có thể. Thực hiện theo các liên kết để biết thêm chi tiết.
Erwin Brandstetter

21

Hãy thử cái này:

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

Xem SQLFiddle này


1
Có một tùy chọn khác bằng cách sử dụng hàm cửa sổ rank ().
Denis de Bernardy

@ user1735921: Bạn sẽ nhận được tất cả các cột từ Table1. Bạn có thể chọn bất kỳ cái nào bạn muốn.
Himanshu Jansari

16

Một cách tiếp cận khác là sử dụng first_valuehàm cửa sổ: http://sqlfiddle.com/#!12/7a145/14

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

... mặc dù tôi nghi ngờ đề xuất của ông chủ056 thường sẽ hoạt động tốt hơn khi có các chỉ mục thích hợp.

Giải pháp thứ ba là:

SELECT
  id
FROM (
  SELECT
    id,
    row_number() OVER (PARTITION BY "category" ORDER BY "date" DESC) AS rownum
  FROM Table1
) x
WHERE rownum = 1;

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.