Truy vấn có thể hoạt động như sau:
SELECT a.*
FROM article a
LEFT JOIN (
SELECT DISTINCT ON (article_id)
article_id, value
FROM metrics m
WHERE name = 'score'
ORDER BY article_id, date_created DESC
) m ON m.metrics_id = a.metrics_id
ORDER BY m.value DESC;
Đầu tiên , truy xuất giá trị value
cho name = 'score'
mỗi bài viết trong truy vấn con m
. Giải thích thêm về kỹ thuật được sử dụng trong câu trả lời liên quan này:
Mặc dù vậy, bạn dường như trở thành nạn nhân của một quan niệm sai lầm rất cơ bản:
Không có "trật tự tự nhiên" trong một bảng. Trong một SELECT
, bạn cần ORDER BY
các tiêu chí được xác định rõ. Với mục đích của truy vấn này, tôi giả sử một cột metrics.date_created
. Nếu bạn không có gì thuộc loại này, bạn không có cách nào để xác định "gần đây nhất" và buộc phải quay lại lựa chọn tùy ý từ nhiều hàng đủ điều kiện:
ORDER BY article_id
Đây không phải là không đáng tin cậy. Postgres sẽ chọn một hàng khi nó chọn. Có thể thay đổi với bất kỳ cập nhật nào đối với bảng hoặc bất kỳ thay đổi nào trong kế hoạch truy vấn.
Tiếp theo , LEFT JOIN
vào bảng article
và ORDER BY value
. NULL
sắp xếp cuối cùng, vì vậy các bài viết không có giá trị đủ điều kiện sẽ được xếp sau cùng.
Lưu ý:một số ORM không quá thông minh (và tôi e rằng ActiveRecord của Ruby là một trong số đó) sử dụng id
không mang tính mô tả và không phân biệt làm tên cho khóa chính. Bạn sẽ phải điều chỉnh cho phù hợp với tên cột thực tế mà bạn không cung cấp.
Hiệu suất
Nên đàng hoàng. Đây là một truy vấn "đơn giản" theo như Postgres có liên quan. Chỉ mục nhiều cột một phần trên metrics
sẽ làm cho nó nhanh hơn:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Các cột theo thứ tự này. Trong PostgreSQL 9.2+, bạn có thể thêm giá trị cột để có thể quét chỉ mục:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';