带有条件的条件活动记录查询

时间:2015-09-15 22:38:52

标签: sql ruby-on-rails activerecord model-view-controller rails-activerecord

默认情况下:completed_at为nil。如果我使用完整方法,那么completed_at将变为Time.now。我检查了它,它工作正常。 尽管如此,我的查询在传入/传出任务的情况下不起作用。查询与已完成的任务完美匹配真是奇怪。所以"其中"查询不起作用,但" where.not"确实。你能帮我解决这个问题吗?

def incoming_tasks
  @user =current_user
  @executed_tasks = @user.executed_tasks.where("completed_at = ?", 'nil').order("created_at DESC")
end

def outgoing_tasks
  @user = current_user
  @assigned_tasks = @user.assigned_tasks.where("completed_at = ?", 'nil').order("created_at DESC")
end

def completed_tasks
  @user = current_user
  @assigned_tasks = @user.assigned_tasks.where.not("completed_at = ?", 'nil').order("completed_at DESC")
  @executed_tasks = @user.executed_tasks.where.not("completed_at = ?", 'nil').order("completed_at DESC")
end

以下是我使completed_at属性具有日期的方式:

def complete
  @task = Task.find(params[:id])
  @task.update_attribute(:completed_at, Time.now)
  redirect_to completed_tasks_user_tasks_path(current_user)
end

1 个答案:

答案 0 :(得分:2)

如上所述,您需要使用IS关键字生成SQL,以确定列是否为NULL。您可以将哈希值传递给where,让ActiveRecord处理微妙之处,而不是自己争吵;即:

def incoming_tasks
  @user =current_user
  @executed_tasks = @user.executed_tasks.where(completed_at: nil).order("created_at DESC")
end

def outgoing_tasks
  @user = current_user
  @assigned_tasks = @user.assigned_tasks.where(completed_at: nil).order("created_at DESC")
end

def completed_tasks
  @user = current_user
  @assigned_tasks = @user.assigned_tasks.where.not(completed_at: nil).order("completed_at DESC")
  @executed_tasks = @user.executed_tasks.where.not(completed_at: nil).order("completed_at DESC")
end

顺便说一句,这将是一个使用范围的好地方。

修改详细信息:

(警告:SQL是一个规范,而不是一个实现,rails生成的SQL依赖于数据库适配器。以下内容可能因您选择的数据库而异。)

好的,有些事情:

  1. 您正在使用where("completed_at = ?", 'nil'),它实际上正在查找completed_at字符串 "nil"的记录。这几乎肯定不是你想要的,并且还有其他意想不到的后果。

  2. 在匹配行时,SQL有一种非常特殊的方法来处理NULL值。在=子句中使用WHERE运算符时,它将忽略具有NULL值的行。您必须使用其中一个IS NULLIS NOT NULL运算符来推理NULL值。

  3. 考虑一下表:

    | id | completed_at               |
    
    | 1  | 2015-07-11 23:23:19.259576 |
    | 2  | NULL                       |
    

    使用以下查询:

    Rails                                | SQL                                | Result
    
    where("completed_at = ?", 'nil')     | WHERE (completed_at = 'nil')       | nothing, since completed_at isn't even a string
    where.not("completed_at = ?", 'nil') | WHERE (NOT (completed_at = 'nil')) | only row 1, since = can't match a NULL value, even when negated
    where("completed_at = ?", nil)       | WHERE (completed_at = NULL)        | nothing, you can't test for NULL with the = operator
    where.not("completed_at = ?", nil)   | WHERE (NOT (completed_at = NULL))  | nothing, you can't test for not NULL with = either
    where(completed_at: nil)             | WHERE completed_at IS NULL         | row 2 only
    where.not(completed_at: nil)         | WHERE (completed_at IS NOT NULL)   | row 1 only
    

    当然,where(completed_at: nil)只是where('completed_at IS NULL')的简写,反之亦然,但哈希格式更加惯用且独立于数据库适配器。

    所有这一切的神奇之处在于ActiveRecord能够通过查看传递给=的哈希来确定它是否应该使用IS NULLwhere。如果你传递一个片段,它就不知道了,所以它盲目地应用它。