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


183

我正在尝试运行以下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());

这将产生以下错误:

查询失败:错误:关系“ sf_bands”不存在

在所有示例中,我都能找到有人指出该关系不存在的错误,这是因为他们在表名中使用大写字母。我的表格名称没有大写字母。有没有一种方法可以查询我的表而不包含数据库名称,即showfinder.sf_bands


2
您确定sf_bands表存在吗?showfinder.sf_bands是否起作用?
brian-巴西

1
showfinder.sf_bands完美运作
Keyslinger 2009年

也许我应该注意到,我的数据库从MySQL被迁移
Keyslinger

你可以尝试pg_query($ dbconn,$ query)吗?隐式连接可能导致难以调试的问题,也可能将其消除为可能的问题。您还可以尝试使用pg_dbname($ dbconn)来确保它确实已连接到showfinder吗?
brian-巴西2009年

1
+1表示大写字母是问题所在。我花了一个小时试图弄清楚为什么我无法从PostgreSQL的单个表中进行选择。多么糟糕的程序。
Brain2000

Answers:


296

根据我的阅读,此错误表示您未正确引用表名。一个常见的原因是该表是使用大小写混合的拼写定义的,而您正在尝试使用所有小写字母对其进行查询。

换句话说,以下操作失败:

CREATE TABLE "SF_Bands" ( ... );

SELECT * FROM sf_bands;  -- ERROR!

使用双引号分隔标识符,以便在定义表时可以使用特定的大小写混合拼写。

SELECT * FROM "SF_Bands";

作为您的注释,您可以将架构添加到“ search_path”,以便在引用表名而不限定其架构时,查询将通过按顺序检查每个架构来匹配该表名。就像PATH在shell或include_pathPHP中一样。您可以检查当前的架构搜索路径:

SHOW search_path
  "$user",public

您可以更改架构搜索路径:

SET search_path TO showfinder,public;

另请参见http://www.postgresql.org/docs/8.3/static/ddl-schemas.html


糟糕,请原谅我。我的意思是说我的表名没有大写字母,而不是数据库名。
Keyslinger 2009年

13
看来,即使您键入SELECT * FROM SF_Bands该命令仍然会失败,因为Postgres决定为您小写该表名。很奇怪...
Roman Starkov 2011年

3
@romkyns:是的,这实际上在RDBMS品牌中非常普遍,未分隔的标识符被宣传为“不区分大小写”。但是它们并不是真正不区分大小写的,因为它们的实现方式是强制小写。仅当在定义表时允许将表名转换为小写时,此表才与表名匹配。如果在创建表时使用双引号分隔符,则在查询中引用它时必须使用分隔符。
比尔·卡文

如果表名不在引号中,则Postgres自动将其小写吗?那真是太愚蠢了……
Andy

@Andy,当您编写自己的SQL数据库时,可以通过其他方式随意实现不区分大小写的标识符。:)
Bill Karwin

76

我对此有疑问,这就是故事(很伤心,但事实如此):

  1. 如果您的表名全部为小写字母,例如:帐户,则可以使用:select * from AcCounTs,它将正常工作

  2. 如果您的表名都是小写,例如:accounts 以下操作将失败: select * from "AcCounTs"

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

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

我不喜欢记住这种无用的东西,但是你必须;)


1
位置从句中的列名相同
Roland

8
5.混合大小写,例如Accounts,将失败,select * from Accounts;因为我找到了最奇怪的部分:相同大小写不相同。
罗兰2014年

7
就是这样:除非使用引号,否则postgres查询中的所有名称均为小写。
Erndob

1
第四个选项对我
有用

2
感谢您安排所有互动!:)
GetHacked

16

Postgres处理查询不同于其他RDMS。将表名这样的模式名放在双引号之前,例如“ SCHEMA_NAME”。“ SF_Bands”


7
您的答案与之前接受的答案有什么不同,被投票了22次并且有很多细节?
Yaroslav

16

将dbname参数放在您的连接字符串中。它对我有用,而其他所有失败。

另外,在进行选择时,请指定your_schemayour_table像这样:

select * from my_schema.your_table

1
将架构名称(例如my_schema.my_relation)放入查询中会有所帮助。
JoeTidee

2
非常感谢你!它确实可以帮助我解决问题!但是有办法我可以省略方案名称吗?
夏洛特

8

我在OSX上遇到了类似的问题,但尝试使用双引号和单引号。对于您的情况,您可以尝试这样的事情

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

4

这真的很有帮助

SET search_path TO schema,public;

我进一步研究了此问题,并了解了如何通过默认方式为当前数据库中的新用户设置此“ search_path”。

打开数据库属性,然后打开工作表“变量”,并简单地为您的用户添加带有实际值的此变量。

因此,现在您的用户将通过默认获得此schema_name,并且可以使用不带schemaName的tableName。


4

您必须在引用标记中写模式名称和表名称。如下:

select * from "schemaName"."tableName";

1

对我来说,问题是,在初始化Django时,我曾使用过对该特定表的查询。当然,这将引发错误,因为这些表不存在。就我而言,它是get_or_createadmin.py文件中的一种方法,只要软件运行任何类型的操作(在本例中为迁移),该方法便会执行。希望能对某人有所帮助。


0

您必须先添加架构,例如

SELECT * FROM place.user_place;

如果您不想在所有查询中添加它,请尝试以下操作:

SET search_path TO place;

现在它将起作用:

SELECT * FROM user_place;

0

最简单的解决方法是将表名和所有列名更改为小写即可解决问题。

例如:

  • 更改Table_Nametable_name
  • 更改ColumnNamecolumnname
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.