Bạn có thể tìm hành khách có tên dài nhất cho mỗi nhóm một cách thuận tiện với DISTINCT ON
.
Nhưng tôi không thấy có cách nào để kết hợp điều đó (hoặc bất kỳ cách đơn giản nào khác) với truy vấn ban đầu của bạn trong một SELECT
duy nhất . Tôi khuyên bạn nên tham gia hai truy vấn phụ riêng biệt:
SELECT *
FROM ( -- your original query
SELECT orig
, count(*) AS flight_cnt
, count(distinct passenger) AS pass_cnt
, percentile_cont(0.5) WITHIN GROUP (ORDER BY bags) AS bag_cnt_med
FROM table1
GROUP BY orig
) org_query
JOIN ( -- my addition
SELECT DISTINCT ON (orig) orig, passenger AS pass_max_len_name
FROM table1
ORDER BY orig, length(passenger) DESC NULLS LAST
) pas USING (orig);
USING
trong mệnh đề tham gia thuận tiện chỉ xuất ra một phiên bản của orig
, vì vậy bạn có thể chỉ cần sử dụng SELECT *
trong SELECT
bên ngoài .
Nếu passenger
có thể là NULL, điều quan trọng là phải thêm NULLS LAST
:
Từ nhiều tên hành khách có cùng độ dài tối đa trong cùng một nhóm, bạn sẽ có lượt chọn tùy ý - trừ khi bạn thêm nhiều biểu thức hơn vào ORDER BY
như tiebreaker. Giải thích chi tiết trong câu trả lời được liên kết ở trên.
Hiệu suất?
Thông thường, một lần quét vượt trội hơn, đặc biệt là với các lần quét tuần tự.
Truy vấn trên sử dụng hai quét (có thể quét chỉ mục / chỉ mục). Nhưng lần quét thứ hai tương đối rẻ trừ khi bảng quá lớn để chứa trong bộ nhớ cache (chủ yếu). Lukas đã đề xuất một truy vấn thay thế chỉ với một đơn SELECT
thêm:
, (ARRAY_AGG (passenger ORDER BY LENGTH (passenger) DESC))[1] -- I'd add NULLS LAST
Ý tưởng này thật thông minh, nhưng lần cuối tôi đã thử nghiệm
, array_agg
với ORDER BY
đã không hoạt động quá tốt. (Chi phí của mỗi nhóm ORDER BY
là quan trọng và việc xử lý mảng cũng tốn kém.)
Cách tiếp cận tương tự có thể rẻ hơn với hàm tổng hợp tùy chỉnh first()
như được hướng dẫn trong Postgres Wiki tại đây
. Hoặc nhanh hơn, với phiên bản được viết bằng C, có sẵn trên PGXN
. Loại bỏ chi phí bổ sung cho việc xử lý mảng, nhưng chúng tôi vẫn cần ORDER BY
cho mỗi nhóm . Có thể nhanh hơn chỉ dành cho một số nhóm. Sau đó, bạn sẽ thêm:
, first(passenger ORDER BY length(passenger) DESC NULLS LAST)
Gordon
và Lukas
cũng đề cập đến hàm cửa sổ first_value()
. Các chức năng của cửa sổ được áp dụng sau Chức năng tổng hợp. Để sử dụng nó trong cùng một SELECT
, chúng tôi cần tổng hợp passenger
bằng cách nào đó đầu tiên - bắt 22. Gordon giải quyết vấn đề này bằng một truy vấn con - một ứng cử viên khác cho hiệu suất tốt với Postgres tiêu chuẩn.
first()
thực hiện tương tự mà không cần truy vấn con và sẽ đơn giản hơn và nhanh hơn một chút. Nhưng nó vẫn sẽ không nhanh hơn một DISTINCT ON
riêng biệt đối với hầu hết các trường hợp có ít hàng cho mỗi nhóm. Đối với nhiều hàng trên mỗi nhóm, kỹ thuật CTE đệ quy thường nhanh hơn. Có những kỹ thuật nhanh hơn nếu bạn có một bảng riêng chứa tất cả các orig
có liên quan, duy nhất các giá trị. Chi tiết:
Giải pháp tốt nhất phụ thuộc vào các yếu tố khác nhau. miếng bánh pudding đang bị ăn dở. Để tối ưu hóa hiệu suất, bạn phải kiểm tra thiết lập của mình. Truy vấn trên phải là một trong những truy vấn nhanh nhất.