我想使用psycopg2的sql子模块来编写干净的动态SQL:
from psycopg2 import sql
...
cursor.execute(sql.SQL("SELECT * FROM {}").format(sql.Identifier('myschema.mytable'))
这将创建以下查询:
SELECT * FROM "myschema.mytable"
这里我遇到了
Relation "myschema.mytable" not found.
异常。
如何正确处理模式名称?以下语句可行,但如何使用 psycopg2 创建它们?
SELECT * FROM myschema.mytable
SELECT * FROM myschema."mytable"
SELECT * FROM "myschema"."mytable"
编辑:澄清架构前缀
施工
sql.Identifier('myschema.mytable')
被视为单个带引号的标识符,从生成的查询中可以看出。 请参阅@gg的答案,了解自 2.8 版本以来如何在 Psycopg 中处理合格标识符。
(对于旧版本)您应该将架构和表名称作为单独的标识符传递以进行格式化:
cursor.execute(sql.SQL("SELECT * FROM {}.{}").format(
sql.Identifier('myschema'),
sql.Identifier('mytable'))
请注意,模式和表名称必须完全匹配,大小写和全部匹配,因为
psycopg2
的 SQL 字符串组合工具 会生成带引号的标识符,并且带引号的标识符区分大小写。
但是我的 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"
即您需要一个单独的模式标识符和单独的由
.
连接的表。
自版本 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