bạn không thể làm một cách đơn giản .group(:name)
vì đó tạo ra một GROUP BY name
trong SQL của bạn khi bạn sẽ chọn ungrouped và unaggregate d cột, rằng lá mơ hồ như mà hàng để chọn và PostgreSQL (rightly IMHO) complains:
When GROUP BY is present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions, since there would be more than one possible value to return for an ungrouped column.
Nếu bạn bắt đầu thêm nhiều cột để nhóm của bạn với một cái gì đó như thế này:
T.group(T.columns.collect(&:name))
sau đó bạn sẽ được nhóm bởi những điều bạn không muốn và cuối cùng bạn sẽ rút toàn bộ bảng và đó không phải là điều bạn muốn. Nếu bạn cố gắng tổng hợp để tránh vấn đề nhóm, bạn sẽ kết thúc trộn các hàng khác nhau (tức là một cột sẽ đến từ một hàng trong khi một cột khác sẽ đến từ một số hàng khác) và đó không phải là thứ bạn muốn.
ActiveRecord thực sự không được xây dựng cho loại điều này nhưng bạn có thể uốn cong nó theo ý muốn của bạn với một số nỗ lực.
Bạn đang sử dụng AR để bạn có thể có cột id
. Nếu bạn có PostgreSQL 8.4 hoặc cao hơn, sau đó bạn có thể sử dụng window functions làm một loại GROUP BY được bản địa hoá; bạn sẽ cần phải cửa sổ hai lần: một lần để tìm ra các cặp name
/thedate
và một lần nữa để chỉ chọn một id
(chỉ trong trường hợp bạn có nhiều hàng với cùng một name
và thedate
khớp với sớm nhất thedate
) và do đó nhận được một hàng duy nhất :
select your_table.*
from your_table
where id in (
-- You don't need DISTINCT here as the IN will take care of collapsing duplicates.
select min(yt.id) over (partition by yt.name)
from (
select distinct name, min(thedate) over (partition by name) as thedate
from your_table
) as dt
join your_table as yt
on yt.name = dt.name and yt.thedate = dt.thedate
)
Sau đó, bọc trong find_by_sql
và bạn có đối tượng của mình.
Nếu bạn đang sử dụng Heroku với cơ sở dữ liệu được chia sẻ (hoặc một số môi trường khác không có 8.4 hoặc cao hơn), thì bạn bị kẹt với PostgreSQL 8.3 và bạn sẽ không có chức năng cửa sổ. Trong trường hợp đó, bạn có thể muốn để lọc ra các bản sao trong Ruby-đất:
with_dups = YourTable.find_by_sql(%Q{
select yt.*
from your_table yt
join (select name, min(thedate) as thedate from your_table group by name) as dt
on yt.name = dt.name and yt.thedate = dt.thedate
});
# Clear out the duplicates, sorting by id ensures consistent results
unique_matches = with_dups.sort_by(&:id).group_by(&:name).map { |x| x.last.first }
Nếu bạn khá chắc chắn rằng sẽ không có trùng lặp name
/min(thedate)
cặp sau đó là giải pháp 8.3 tương thích với sức mạnh là đặt cược tốt nhất của bạn; nhưng, nếu có rất nhiều bản sao, thì bạn muốn cơ sở dữ liệu thực hiện càng nhiều công việc càng tốt để tránh tạo hàng nghìn đối tượng AR mà bạn sắp bỏ đi.
Có thể một người nào đó có mạnh mẽ hơn PostgreSQL-Fu hơn tôi sẽ đến và cung cấp một cái gì đó đẹp hơn.
Điều này có các vấn đề về tính duy nhất nếu cặp 'name, min (date)' xuất hiện hai lần trong bảng. –