Truy vấn PostgreSQL với ngày tối đa và tối thiểu cộng với id được liên kết trên mỗi hàng


7

Tôi có bảng sau:

CREATE TABLE trans (
    id SERIAL PRIMARY KEY,
    trans_date date,
    trans_time time        
);

Tôi muốn có quan điểm sau

CREATE OR REPLACE VIEW daily_trans AS
SELECT trans_date,
    max(trans_time) as first, 
    min(trans_time) as last,
    calculate_status(min(trans_time), max(trans_time)) as status 
GROUP BY trans_date 

với các cột chỉ định id của max và min trans_time.

Làm thế nào để làm điều đó?

Câu trả lời:


10

Bạn có thể tính toán điều này trong một bước với các chức năng của cửa sổ :

CREATE OR REPLACE VIEW daily_trans AS
SELECT DISTINCT
       trans_date
     , first_value(trans_time) OVER w AS first_time
     , first_value(id)         OVER w AS first_id
     , last_value(trans_time)  OVER w AS last_time
     , last_value(id)          OVER w AS last_id
     , calculate_status(min(trans_time) OVER w
                      , max(trans_time) OVER w) AS status 
FROM   trans
WINDOW w AS (PARTITION BY trans_date ORDER BY trans_time, id
             ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
ORDER  BY 1;

Tôi đã thêm iddưới dạng ORDERcột phụ trong mệnh đề cửa sổ, để làm cho thứ tự sắp xếp ổn định trong trường hợp thời gian giống hệt nhau mỗi ngày.

Nếu bạn không quen với các chức năng của cửa sổ, hãy nhớ đọc chương này của hướng dẫn .

ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWINGlà một mệnh đề không được sử dụng phổ biến để điều chỉnh khung cửa sổ, bởi vì chúng tôi muốn last_value()luôn trả về giá trị cuối cùng của toàn bộ phân vùng (ngày), chứ không phải giá trị cuối cùng cho đến hiện tại (bao gồm cả các đồng nghiệp) theo thứ tự sắp xếp.

Cách bạn kết hợp DISTINCTvới các chức năng của cửa sổ:


Cảm ơn bạn @Erwin Brandstetter, đó là một câu trả lời tuyệt vời.
Joe ngẫu nhiên

4

Roughly, bạn muốn một cái gì đó như

select min_trans_time, min_trans.id as min_trans_time_id,
       max_trans_time, max_trans.id as max_trans_time_id
from (
    select   trans_date,
             max(trans_time) as max_trans_time, 
             min(trans_time) as min_trans_time,
    from     trans        
    group by trans_date) min_max_trans,
       trans as min_trans,
       trans as max_trans
where min_trans.trans_time = min_max_trans.min_trans_time
and   max_trans.trans_time = min_max_trans.max_trans_time

Điều này có thể không ổn định nếu một số transes chia sẻ giống nhau trans_time(nghĩa là chạy truy vấn trên cùng một bộ dữ liệu có thể mang lại kết quả khác nhau. Một cách dễ dàng để giải quyết vấn đề này, nếu đó là một mối quan tâm, là chọn id tối đa hoặc tối thiểu, ví dụ. Tất nhiên, điều này có thể làm sai lệch kết quả :).

Bạn cũng có thể sử dụng Hàm cửa sổ nếu bạn đang sử dụng PostgreSQL 8.4 trở lên; họ sẽ cung cấp một truy vấn rõ ràng hơn (rõ ràng nếu bạn quen thuộc với các chức năng của cửa sổ :) và họ cho phép bạn thực hiện những công việc khá khó thực hiện với chiến lược trên (ví dụ: lấy giá trị cao thứ 2 thay vì tối đa). Tuy nhiên, theo kinh nghiệm ngắn ngủi của tôi, họ thực hiện kém hơn so với phương pháp tự tham gia mà tôi đề xuất ở đây. Câu trả lời của Erwin chứa một phiên bản của truy vấn bằng các hàm cửa sổ. Sẽ rất thú vị khi lưu ý truy vấn nào thực thi tốt hơn và / hoặc có thể được tối ưu hóa tốt hơn (bằng cách thêm các chỉ mục, v.v.).


+1 để xem xét thời gian không duy nhất mỗi ngày (mặc dù bạn không giải quyết được điều đó) và đề cập đến các chức năng của cửa sổ (mặc dù bạn không sử dụng chúng).
Erwin Brandstetter

Tôi đã nâng cấp của bạn. Tôi đề xuất giải pháp này và giữ nó ở đây vì các chức năng của cửa sổ không có sẵn rộng rãi trong tất cả các RDBMS, cũng không được tiêu chuẩn hóa và bởi vì chúng có thể ít hoạt động hơn. Tuy nhiên, tôi sẽ chỉnh sửa một chút câu trả lời của mình ...
alex

2
Trên thực tế, các hàm cửa sổ nằm trong tiêu chuẩn SQL: 2003 và được hỗ trợ bởi tất cả các RDBMS chính (Oracle, PostgreQuery, SQL Server, ...) Ngoại lệ đáng chú ý duy nhất là MySQL. Nhưng một lần nữa, MySQL thậm chí không hỗ trợ CTE (một tiêu chuẩn SQL quan trọng khác).
Erwin Brandstetter

Có phải họ không? Tôi nghĩ rằng mỗi RDBMS sử dụng cú pháp khác nhau. Nếu đúng như vậy, tôi nghĩ rằng giới hạn / độ lệch không được chuẩn hóa (đó không phải là lần cuối tôi kiểm tra, IIRC- mặc dù đã lâu rồi).
alex

2
RDBMS sử dụng cú pháp hơi khác nhau cho hầu hết mọi chi tiết. RDBMS tuân thủ tiêu chuẩn nhất hiện có lẽ là PostgreSQL. Điều đó không thay đổi thực tế là các tiêu chuẩn SQL tồn tại và những người chơi chính thực hiện chúng hầu hết.
Erwin Brandstetter
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.