查找集合的最后一个匹配记录

时间:2012-02-27 23:40:35

标签: ruby-on-rails ruby ruby-on-rails-3 postgresql

我有一个我想写的功能,无法弄清楚它是如何工作的。第一行按照它们应该的顺序返回我的步骤,第二行我想返回课程所有步骤中的最后一个匹配步骤。我想我很接近,但需要知道我做错了什么。

course_steps_in_order = course.steps.sort_by(&:component_and_step_order)    
last_completed_step = current_user.completed_steps.where("steps.id in ?", course_steps_in_order).last

我收到了错误...

ActiveRecord::StatementInvalid: PG::Error: ERROR:  syntax error at or near "1"
LINE 1: ... WHERE "user_steps"."user_id" = 3 AND (step.id in 1,2,4,8,5,...
                                                         ^
: SELECT  "steps".* FROM "steps" INNER JOIN "user_steps" ON "steps"."id" = "user_steps"."step_id" WHERE "user_steps"."user_id" = 3 AND (step.id in 1,2,4,8,5,3,7,6,9) ORDER BY "steps"."id" DESC LIMIT 1

根据以下模型,课程有很多组成部分,步骤很多......

class Course < ActiveRecord::Base
  has_many :components, :dependent => :destroy, :order => "component_order"
  has_many :steps, :through => :components, :dependent => :destroy
end

class Component < ActiveRecord::Base
  belongs_to :course
  has_many :steps, :dependent => :destroy, :order => "step_order"
end

class Step < ActiveRecord::Base
  belongs_to :component

  def component_and_step_order
    component_order * 100 + step_order
  end
end

2 个答案:

答案 0 :(得分:3)

你有两个问题:一个你知道,一个你不知道。第一个也是最明显的问题是clyfe为您解决的SQL语法错误。第二个问题是IN不保证任何特定的顺序,所以:

current_user.completed_steps.where("steps.id in (?)", course_steps_in_order).last

不保证会为您提供id位于course_steps_in_order的最后一步,甚至不保证从一次执行到下一次执行会产生相同的结果。如果要按特定顺序从SQL中获取结果,必须使用ORDER BY子句显式指定该顺序。例如,我刚刚在我的一个PostgreSQL表中执行了此操作:

=> select id from some_table where id in (1,2,3,4,5);
 id 
----
  1
  5
  2
  3
  4

当您期望4时,您的方法会将5作为最后一个。

请允许我重复一遍:关系数据库是基于设置而且本质上是无序的,如果您需要按特定顺序执行任何操作,那么必须明确指定ORDER BY子句中的顺序。

如果您希望last来电显示有用的内容,则需要将component_and_step_order方法转换为.order来电,并将其包含在current_user.completed_steps.where查询中。< / p>

答案 1 :(得分:2)

添加包含括号的括号:

...
last_completed_step = current_user.completed_steps.where("steps.id in (?)", course_steps_in_order).last

现在查询将正确生成:

... AND (step.id in (1,2,4,8,5))