Nếu bạn không ngại làm bẩn tay với một chút SQL, bạn có thể sử dụng chức năng cửa sổ để hoàn thành công việc. Bạn có thể lấy ID bài đăng bằng SQL này:
select id
from (
select id,
rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = #{user.id}
) as dt
where rank = 1
Nếu bạn muốn nhiều cột hơn, hãy thêm chúng vào cả hai mệnh đề CHỌN. #{user.id}
tất nhiên là người nhận mà bạn quan tâm.
Phần thú vị là chức năng cửa sổ:
rank() over (partition by thread_id order by created_at desc)
Thao tác này sẽ phân vùng bảng thành các nhóm dựa trên thread_id
(loại GROUP BY được bản địa hóa), sắp xếp chúng theo dấu thời gian (gần đây nhất trước), rồi đến rank()
mang lại 1 cho mục nhập đầu tiên trong mỗi nhóm, 2 cho mục thứ hai, v.v.
Cho một bảng giống như sau:
=> select * from posts;
id | receiver_id | thread_id | created_at
----+-------------+-----------+---------------------
1 | 1 | 2 | 2011-01-01 00:00:00
2 | 1 | 2 | 2011-02-01 00:00:00
3 | 1 | 2 | 2011-03-01 00:00:00
4 | 1 | 3 | 2011-01-01 00:00:00
5 | 1 | 4 | 2011-01-01 00:00:00
6 | 1 | 3 | 2011-01-01 13:00:00
7 | 2 | 11 | 2011-06-06 11:23:42
(7 rows)
Truy vấn bên trong cung cấp cho bạn điều này:
=> select id, rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = 1;
id | rank
----+------
3 | 1
2 | 2
1 | 3
6 | 1
4 | 2
5 | 1
(6 rows)
Và sau đó, chúng tôi bao bọc truy vấn bên ngoài xung quanh điều đó để chỉ loại bỏ các kết quả phù hợp xếp hạng hàng đầu:
=> select id
from (
select id,
rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = 1
) as dt
where rank = 1;
id
----
3
6
5
(3 rows)
Vì vậy, hãy thêm các cột bổ sung bạn muốn và gói gọn tất cả trong Post.find_by_sql
và bạn đã hoàn tất.