ActiveRecord::StatementInvalid SQLite3::SQLException: 没有这样的列:true:

7
我希望@messages返回@folder.messages,其中列“deleted”的值不等于true。我不确定为什么会抛出SQLException。我猜我没有正确格式化删除的属性,但我不知道如何修复它。
任何帮助将不胜感激。提前致谢。
错误信息:
ActiveRecord::StatementInvalid in MailboxController#index  
SQLite3::SQLException: no such column: true: SELECT     "message_copies".* FROM       "message_copies"  WHERE     ("message_copies".folder_id = 1) AND (deleted != true)  

应用程序跟踪:

app/controllers/mailbox_controller.rb:14:in `show'  
app/controllers/mailbox_controller.rb:5:in `index'  

Mailbox_Controller.rb

1   class MailboxController < ApplicationController  
2     def index  
3       current_user = User.find(session[:user_id])  
4       @folder = Folder.where("user_id = #{current_user.id}").first  
5       show  
6       render :action => "show"  
7     end
8  
9     def show  
10      current_user = User.find(session[:user_id])  
11      @folder = Folder.where("user_id = #{current_user.id}").first  
12      @msgs = @folder.messages  
13      @ms = @msgs.where("deleted != true")  
14      @messages = @ms.all.paginate :per_page => 10,  
15                 :page => params[:page], :include => :message,  
16                 :order => "messages.created_at DESC"  
17    end  
18  end  
3个回答

21

SQLite使用C风格的布尔值

SQLite没有单独的布尔存储类。相反,布尔值以整数0(false)和1(true)的形式存储。

因此,当您这样说时:

deleted != true

SQLite不知道true是什么,因此它会认为你试图引用另一个列名。

正确的处理方式是让AR将你的Ruby布尔值转换为SQLite布尔值(参见Tam和fl00r的答案)。我认为了解你做错了什么很有用。

更新:如果你想检查非true的deleted并包括NULL,则需要使用以下代码:

@ms = @msgs.where("deleted != ? OR deleted IS NULL", true)

或者更好的方法是,在deleted中根本不允许NULL。除非必须这样做(ActiveRecord默认的空值设置与应该设置的恰恰相反),否则不应该在任何列中允许NULL。SQL NULL是一个奇怪的存在,你总是需要特别对待它,最好不要允许它,除非你需要一个“不存在”或“未指定”列值。


我原以为它存储t/f对。但是我可能错了 :). 但现在我看了你的链接 - 我错了 :) 但有人确实存储了t/f。肯定的! - fl00r
谢谢解释,非常有帮助。只是为了确保我对SQL的理解正确...当处理空值时,它是如何处理的?通过说!= 1(true),它是否还会返回具有空值的行?再次感谢。 - user714001
如果你想捕获NULL值,那么你需要在WHERE子句中添加一个明确的deleted IS NULLdeleted = NULL在任何数据库中都不起作用,因为x = NULL对于所有x都是false(即使x本身是NULL)。我添加了一个关于NULL的快速更新。 - mu is too short
@fl00r:我不认为@msgs.where("deleted != ?", nil)会起作用,因为AR会将其转换为deleted != NULL。由于NULL的独特特性,任何与NULL的比较都必须使用x IS NULLx IS NOT NULL来完成。 - mu is too short
1
@fl00r:你确定它会重写SQL片段吗?我刚刚快速跟踪了AR3代码,我看到像statement.gsub('?')这样的东西,但没有任何特殊情况下将=更改为IS的内容。不过,我认为发送{ :deleted => nil }应该可以解决问题。 - mu is too short
显示剩余8条评论

3
@ms = @msgs.where("deleted != ?", true) 
# OR
@ms = @msgs.where(:deleted => false) 
true对于不同的数据库有所不同。在一些数据库中,它是t/f值,在一些数据库中是true/false,因此您应该将其放在引号中,并确保它适用于您特定的数据库,或者您应该将其排除在您的SQL之外,这样Rails就会为您完成工作。
更新:如果deletedNULL。首先,默认情况下将删除字段设置为false。其次,如何使用AR查找:
@ms = @msgs.where("deleted = ? OR deleted = ?", false, nil)
# wich won't work, Thanks to @mu is too short
@ms = @msgs.where("deleted = ? OR deleted IS NULL", false)

0

尝试

@ms = @msgs.where(["deleted != ?",true])

好的,它不再抛出错误了,所以这很好。但它仍然没有返回我想要的结果。还有一个问题,根据语句的写法...我假设它也应该返回"deleted"没被设置的值(即不等于真或假值),我的假设是正确的吗? - user714001
这个代码只会返回那些为真的值。如果你想要返回那些为空的值,可以尝试这样做:@ms = @msgs.where(["deleted is NULL OR deleted != ?",true])。 - Tam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接