Psycopg2标识符中的模式名称

8
我想使用psycopg2的sql子模块编写干净的动态SQL语句:
from psycopg2 import sql
...
cursor.execute(sql.SQL("SELECT * FROM {}").format(sql.Identifier('myschema.mytable'))

这会创建以下查询:
SELECT * FROM "myschema.mytable"

在这里,我遇到了一个异常:关系“myschema.mytable”未找到。

我该如何正确处理模式名称?以下语句可行,但我应该如何使用psycopg2创建它们?

SELECT * FROM myschema.mytable
SELECT * FROM myschema."mytable"
SELECT * FROM "myschema"."mytable"

编辑:澄清模式前缀


我刚在DBeaver中尝试了一下:SELECT * FROM mytable;可以正常工作,而SELECT * FROM "mytable";会出错。我必须补充说明的是,mytable包含一个模式前缀,这可能是问题的原因。 - Max
3个回答

10

这个建筑

sql.Identifier('myschema.mytable')

如生成的查询所示,该标识符被视为单个带引号的标识符。您应将模式和表名作为单独的标识符传递给格式化程序:

cursor.execute(sql.SQL("SELECT * FROM {}.{}").format(
    sql.Identifier('myschema'),
    sql.Identifier('mytable'))
请注意,模式和表名必须完全匹配,包括大小写,因为psycopg2SQL字符串合成工具生成带引号的标识符,并且带引号的标识符区分大小写。

4
但我的PostgreSQL数据库中的表是有意未加引号的。这意味着mytable存在,但"mytable"不存在。 你误解了引号的作用。在你的情况下(即没有特殊字符的表名),双引号只会使名称区分大小写。如果你有一个名为MyTable的表,则:
SELECT * FROM mytable;

这个工作之所以能够成功是因为它不区分大小写,而

SELECT * FROM "mytable";

由于大小写敏感,它并不会起作用。但是,可以使用其他方法来实现相同的效果。
SELECT * FROM "MyTable";

这是您要寻找的内容,能够正常工作。


另一个问题(如@IljaEverilä在评论中所指出的)是:

SELECT * FROM "myschema.mytable"

Postgres会将其视为名为myschema.mytable的表,因为您已经引用了整个内容。我认为这就是您要寻找的内容:
SELECT * FROM "myschema"."mytable"

即,您需要一个独立的标识符用于模式,另一个独立的标识符用于表格,并通过 . 连接。

感谢解释! - Max

1

自从2.8版本(于2019年4月4日发布)以来,您可以传递多个字符串到sql.Identifier来表示一个合格的标识符(例如模式名称+表名称)。

cursor.execute(
    sql.SQL("SELECT * FROM {table}").format(
        table=sql.Identifier("myschema", "mytable")
    )
)

# SELECT * FROM "myschema"."mytable"

请参见:https://www.psycopg.org/docs/sql.html#psycopg2.sql.Identifier


1
这样好多了,让实际查询保持更简洁。 - undefined

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