无法简单使用PostgreSQL表名(“关系不存在”)

339

我正在尝试运行以下PHP脚本来执行一个简单的数据库查询:

$db_host = "localhost";
$db_name = "showfinder";
$username = "user";
$password = "password";
$dbconn = pg_connect("host=$db_host dbname=$db_name user=$username password=$password")
    or die('Could not connect: ' . pg_last_error());

$query = 'SELECT * FROM sf_bands LIMIT 10';
$result = pg_query($query) or die('Query failed: ' . pg_last_error());

这会产生以下错误:

查询失败:ERROR: 关系 "sf_bands" 不存在

在我找到的所有例子中,当有人收到一个关系不存在的错误时,是因为他们在表名中使用了大写字母。我的表名没有大写字母。有没有一种方法可以查询我的表而不包括数据库名称,例如 showfinder.sf_bands


3
你确定 sf_bands 表存在吗?showfinder.sf_bands 能够使用吗? - brian-brazil
1
showfinder.sf_bands 很完美地运作了。 - Keyslinger
也许我应该注意一下,我的数据库是从MySQL迁移过来的。 - Keyslinger
你能试试 pg_query($dbconn, $query) 吗?隐式连接可能会导致难以调试的问题,最好将其作为可能的问题排除。你也可以尝试使用 pg_dbname($dbconn) 确保它确实连接到 showfinder。 - brian-brazil
4
+1是指大写字母有问题。我花了一个小时来尝试弄清楚为什么无法在PostgreSQL中从单个表中进行选择。这真是个糟糕的程序。 - Brain2000
1
我去掉了表名周围的双引号,现在它可以工作了。 - mercury
19个回答

493
这个错误意味着你没有正确引用表名。一个常见的原因是表名使用了大小写混合的拼写方式,而你试图用全小写进行查询。
换句话说,以下操作会失败:
CREATE TABLE "SF_Bands" ( ... );

SELECT * FROM sf_bands;  -- ERROR!

使用双引号来界定标识符,这样你就可以使用表定义中的特定混合大小写拼写。
SELECT * FROM "SF_Bands";

关于您的评论,您可以向“search_path”添加一个模式,这样当您引用一个没有限定其模式的表名时,查询将按顺序检查每个模式以匹配该表名。就像shell中的PATH或PHP中的include_path一样。您可以检查当前的模式搜索路径:
SHOW search_path
  "$user",public

你可以更改你的模式搜索路径。
SET search_path TO showfinder,public;

阅读有关search_path的更多信息,请点击此处:https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATH

40
似乎即使您键入 SELECT * FROM SF_Bands,这仍将失败,因为Postgres会为您将该表名转换为小写。奇怪... - Roman Starkov
6
是的,这在各种关系型数据库品牌中相当常见,未使用分隔符的标识符被宣传为“不区分大小写”。但实际上它们并非真正的不区分大小写,因为它们的实现方式是强制小写。只有当你在定义表时允许表名变成小写字母形式时,才能匹配表的名称。如果你在创建表时使用了双引号分隔符,那么在查询中引用该表时也必须使用分隔符。 - Bill Karwin
5
如果没有用引号包裹表名,Postgres 会自动将表名转为小写?这相当愚蠢... - Andy
4
@Andy,当你编写自己的SQL数据库时,可以随意使用其他方法实现不区分大小写的标识符。 :) - Bill Karwin
2
在你对PostgreSQL发出无谓的指责之前,请听一下SQL标准的说法:一个<SQL语言标识符>等同于将每个小写字母替换为相应的大写字母或字母组合的<SQL语言标识符>。这种处理包括确定等价性、在信息和定义模式中的表示、在诊断区域中的表示以及类似用途。因此,虽然PostgreSQL不遵循标准,将所有内容转换为小写,但标准要求实现大小写不敏感。 - Laurenz Albe
显示剩余9条评论

104

我遇到了问题,这就是(悲惨但真实的)故事:

  1. 如果您的表名全部小写,例如:accounts 您可以使用:select * from AcCounTs,它将正常工作。

  2. 如果您的表名全部小写,例如:accounts 以下语句会失败: select * from "AcCounTs"

  3. 如果您的表名混合大小写,例如:Accounts 以下语句会失败: select * from accounts

  4. 如果您的表名混合大小写,例如:Accounts 以下语句将正常工作: select * from "Accounts"

我不喜欢记忆这样的无用知识,但您必须要记住;)


1
在where子句中,列名也要相同。 - Roland
9
“Accounts” 这样的混合大小写会导致使用“select * from Accounts;”失败。最奇怪的是,相同大小写并不完全相同。 - Roland
13
要点很简单:在postgres查询中,所有名称都必须小写,除非你使用引号。 - Erndob
1
第四个选项对我有用,尽管我没有使用PHP。 - andy
2
感谢您布置所有的交互! :) - GetHacked

32

Postgres处理查询与其他关系型数据库管理系统不同。在你的表格名之前使用双引号将模式名称括起来,像这样:"SCHEMA_NAME"."SF_Bands"


9
您的回答对已经得到22个赞并且详细说明的先前接受的答案有何补充? - Yaroslav

29

在你的连接字符串中添加dbname参数。尽管其他方法都失败了,但这种方法对我有效。

还要在进行查询时,像这样指定your_schema.your_table

select * from my_schema.your_table

1
将模式名称放入查询中,例如my_schema.my_relation,有助于解决问题。 - JoeTidee
3
非常感谢!这确实帮助我解决了问题!但是我能不能省略方案名称? - Charlotte

20

如果表名包含下划线或大写字母,则需要用双引号括起来。

SELECT * from "Table_Name";

下划线不会造成问题,只有大写字母会。 - not2savvy

14

我在OSX上遇到了类似的问题,但是尝试使用单引号和双引号进行调整。对于你的情况,你可以尝试像这样:

$query = 'SELECT * FROM "sf_bands"'; // NOTE: double quotes on "sf_Bands"

12

您必须使用引号将模式名称和表名称括起来,如下所示:

"模式名称"."表名称"

select * from "schemaName"."tableName";

11

这确实很有帮助

SET search_path TO schema,public;

我进一步调查了这个问题,并了解到如何在当前数据库中为新用户设置默认的“search_path”。

打开数据库属性,然后打开“变量”表格,只需为您的用户添加此变量和实际值即可。

所以现在您的用户将默认获得此模式名称,并且您可以使用没有模式名称的tableName。


4

我遇到了与上述相同的问题,我正在使用PostgreSQL 10.5。 我尝试了上述的所有方法,但似乎没有任何作用。

然后我关闭了pgadmin,打开了PSQL终端会话。 登录PSQL并分别连接到数据库和架构:

\c <DATABASE_NAME>;
set search_path to <SCHEMA_NAME>;

然后,重新启动了pgadmin控制台,接着我就能够在pgadmin的查询工具中无问题地工作。


3
除了Bill Karwin的回答之外,您应该用双引号将表名括起来。但是,请注意,大多数情况下php不允许您只简单地编写:
$query = "SELECT * FROM "SF_Bands"";

相反,应该使用单引号将查询括起来,就像sav所说的那样

$query = 'SELECT * FROM "SF_Bands"';

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