Rails报告找不到一个已经存在的列

6

我目前在尝试使用Rails对一张表进行复杂的WHERE查询,但是我遇到了以下错误:

PG::Error: ERROR:  column "email" does not exist
LINE 1: SELECT "bans".* FROM "bans"  WHERE (Email='' AND IP='' AND (...
                                        ^
: SELECT "bans".* FROM "bans"  WHERE (Email='' AND IP='' AND (Username='NULL' ))

我知道该列实际上是存在的,通过执行rails dbconsole命令可以得到以下结果:

Jungle=> select * from bans;
 id | Username | IP | Email | Reason | Length | created_at | updated_at 
----+----------+----+-------+--------+--------+------------+------------
(0 rows)

所以这肯定在数据库中,有人有这方面的经验吗?

3
你是否在使用大小写敏感的列名来操作PostgreSQL数据库? - Dave Newton
在SQL和表中,大小写完全相同。 - KatGaea
嗯,是的,我想它在一个地方,尽管它所说的缺失列都是小写的。 - Dave Newton
2
@DaveNewton:这是因为PostgreSQL将标识符规范化为小写(尽管标准规定为大写)。 - mu is too short
@muistooshort,啊,懂了。我想是这样,但因为你的好回答再+1。 - Dave Newton
3个回答

12

SQL列名不区分大小写,除非使用引号引用,标准规定标识符应该规范化为大写字母,但是PostgreSQL规范化为小写字母:

对标识符加引号也会使其区分大小写,而未加引号的名称始终折叠为小写字母。例如,PostgreSQL认为标识符FOOfoo"foo"是相同的,而"Foo""FOO"与这三个及彼此都不同。(在PostgreSQL中将未引用的名称折叠为小写字母与SQL标准不兼容,标准规定未引用的名称应折叠为大写字母。因此,根据标准,foo应等价于"FOO"而不是"foo"。如果您想编写可移植的应用程序,建议始终引用特定名称或从不引用它。)

您在SQL中引用了Email:

SELECT "bans".* FROM "bans"  WHERE (Email='' ...

但是PostgreSQL抱怨email:

column "email" does not exist

由于PostgreSQL将标识符规范化为小写,因此您未引号括起来的Email被视为email。听起来像是您通过双引号将列名大写创建:

create table "bans" (
    "Email" varchar(...)
    ...
)

或者使用:Email在迁移中标识列。如果在创建时引用列名,则它不会被规范化为小写(或在SQL标准情况下为大写),您将不得不对其进行双引号引用并永久匹配大小写:

SELECT "bans".* FROM "bans"  WHERE ("Email"='' ...

如果你解决了Email的问题,你还会遇到IPUsernameReasonLength相同的问题:你必须在引用它们的任何SQL中将它们都用双引号括起来。

最佳做法是使用小写的列名和表名,这样你就不必一直担心引用时需要加引号。我建议你将表中的列名改为小写。


另外提一下,你的'NULL'字符串文字:

SELECT "bans".* FROM "bans"  WHERE (Email='' AND IP='' AND (Username='NULL' ))
-- -------------------->------------------>---------->---------------^^^^^^

看起来很奇怪,你确定不是想要使用 "Username" is null 吗?'NULL' 字符串字面量和 NULL 值是完全不同的,你不能使用 =!= 来与 NULL 进行比较,当可能涉及到 NULL 时,你必须使用 is nullis not nullis distinct fromis not distinct from(根据你的意图),来进行比较。


谢谢,那正是问题所在,我只是使用了标准的Rails生成模型等命令。这意味着我现在必须重新编写和打印整个数据库设计文档!无论如何,还是非常感谢您的帮助。 - KatGaea
@nekosune:也许你因为砍伐了那么多树而感到内疚,这会帮助你将来避免这个错误 :) - mu is too short
我为树木感到遗憾,甚至更为工作的批准过程感到遗憾,但是这种奇怪行为所引起的额外工作是必要的。 - KatGaea
遵循Rails的惯例确实可以避免许多混合大小写名称带来的痛苦。 - DGM
我其实不知道 Rails 在这方面的惯例,我真的需要花更多时间学习基础知识。 - KatGaea
这实际上是PostgreSQL最佳实践(未引用的小写标识符)和Ruby / Rails约定(用下划线分隔单词的小写名称)的交集。 - mu is too short

1

我在这里遇到了同样的问题,

但是正如mu-is-too-short所说,PostgreSql可以被告知在列名中区分大小写进行搜索。

因此,通过实现这段代码,我成功地避开了你正在面临的相同错误:

Transaction.find(:all,:conditions => ["(date between ?  and ?) AND \"Membership_id\" = ?", Time.now.at_beginning_of_month,  Time.now.end_of_month,membership.id])

注意到列名周围的\"符号了吗?尽管很烦人,但这是解决问题的方法。

1

看起来你的错误不是来自测试数据库,但如果是的话,请尝试运行rake db:test:prepare

总的来说,请注意你有3个数据库-测试、开发和生产。所以很容易混淆它们并检查错误的数据库。


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