我有一张桌子(其中包括)一个名字和一个等级。我想返回所有唯一名称的集合,但对于返回的每个名称,我想选择排名最高的行。使用两个嵌套的SELECT语句很简单:
SELECT * FROM (SELECT * FROM foo ORDER BY rank DESC) AS ordered GROUP BY name
MySQL为每个名称带来第一个“命中”,这(因为早期的ORDER BY)将始终是排名最高的名称。
现在,如果我想用ActiveRecord连接到这个表,我有点不知所措。我可以把上面的内容扔进find_by_sql
,但这感觉很脏。我试过像
result = foo.all
result.delete_if do |item|
isOutranked = false
result.each do |row|
if (row.name == item.name) and (row.rank > item.rank) then isOutranked = true
end
isOutranked
end
我认为有效,但仍然觉得应该有更好的方法。通过ActiveRecord技巧或更优雅的数组操作来解决它将是受欢迎的!
答案 0 :(得分:2)
MySQL为每个名称带来第一个“命中”,这(因为早期的ORDER BY)将始终是排名最高的名称。
您用于返回组中顶行的查询不保证。这只是实施的巧合,而且可能会发生变化。 不要依赖于此。
您正在尝试解决我经常在StackOverflow上发布的“greatest-n-per-group”问题。这是一个更可靠地得到答案的查询:
SELECT t1.*
FROM foo AS t1
LEFT OUTER JOIN foo AS t2
ON (t1.name = t2.name AND t1.rank < t2.rank)
WHERE t2.name IS NULL;
做同样事情的替代方案:
SELECT *
FROM foo AS t1
WHERE NOT EXISTS
(SELECT * FROM foo AS t2
WHERE t1.name = t2.name AND t1.rank < t2.rank);
我可以把上面的内容扔进
find_by_sql
,但这感觉很脏。
ActiveRecord对于某些类型的查询非常方便,但您无法使用ActiveRecord解决每个数据库查询。越早解决这个问题,你就能越早完成工作并取得成功。 SQL不会咬你。