Redrock Postgres 文档
主页 切换暗/亮/自动模式 切换暗/亮/自动模式 切换暗/亮/自动模式 返回首页

sql – SQL 字符串组成

该模块包含可用于以方便和安全的方式动态生成 SQL 的对象和函数。SQL 标识符(例如表和字段的名称)不能像查询参数一样传递给execute()方法:

# This will not work
table_name = 'my_table'
cur.execute("INSERT INTO %s VALUES (%s, %s)", [table_name, 10, 20])

SQL 查询应该在参数合并之前组成,例如:

# This works, but it is not optimal
table_name = 'my_table'
cur.execute(
    "INSERT INTO %s VALUES (%%s, %%s)" % table_name,
    [10, 20])

这种方法可行,但这是一个等待发生的意外:表名可能是无效的 SQL 文字,需要引用;如果表名来自不受信任的来源,则更严重的是安全问题。该名称应使用escape_identifier()转义:

from psycopg.pq import Escaping

# This works, but it is not optimal
table_name = 'my_table'
cur.execute(
    "INSERT INTO %s VALUES (%%s, %%s)" % Escaping.escape_identifier(table_name),
    [10, 20])

这现在是安全的,但它有点特别。如果出于某种原因,有必要在查询字符串中包含一个值(与在值中相反),合并规则仍然不同。它也仍然相对危险:如果escape_identifier()在某处被遗忘,程序通常会运行,但最终会在包含要转义的字符的表名或字段名时崩溃,或者会出现潜在的可利用弱点。

模块psycopg.sql公开的对象允许动态生成 SQL 语句,将语句的可变部分与查询参数清楚地分开:

from psycopg import sql

cur.execute(
    sql.SQL("INSERT INTO {} VALUES (%s, %s)")
        .format(sql.Identifier('my_table')),
    [10, 20])

模块使用

通常你应该将查询的模板表达为带有{}风格的占位符的SQL实例,并使用format()将可变部分合并到其中,所有这些都必须是Composable子类。您仍然可以在查询中使用%s风格的占位符并将值传递给execute():此类值占位符将不会受到format()的影响:

query = sql.SQL("SELECT {field} FROM {table} WHERE {pkey} = %s").format(
    field=sql.Identifier('my_name'),
    table=sql.Identifier('some_table'),
    pkey=sql.Identifier('id'))

结果对象旨在直接传递给游标方法,例如execute(), executemany(), copy(),但也可以使用as_string()方法将它组合为 Python 字符串查询:

cur.execute(query, (42,))
full_query = query.as_string(cur)

如果您的查询的一部分是可变参数序列,例如以逗号分隔的字段名称列表,您可以使用SQL.join()方法将它们传递给查询:

query = sql.SQL("SELECT {fields} FROM {table}").format(
    fields=sql.SQL(',').join([
        sql.Identifier('field1'),
        sql.Identifier('field2'),
        sql.Identifier('field3'),
    ]),
    table=sql.Identifier('some_table'))

sql 对象

这些sql对象位于以下继承层次结构中:

Composable: 公开公共接口的基类

|__ SQL: SQL 查询的文字片段

|__ Identifier: PostgreSQL 标识符或点号分隔的标识符序列

|__ Literal: 硬编码到查询中的值

|__ Placeholder: 一个%s风格的占位符,其值将在以后添加,例如通过execute()

|__ Composed: Composable实例序列。

Composable 类

class psycopg.sql.Composable

可用于组成 SQL 字符串的对象的抽象基类。

Composable对象可以直接传递给execute(), executemany(), copy() 代替查询字符串。

Composable对象可以使用运算符+进行连接:结果将是一个包含连接对象的Composed实例。运算符*还支持整数参数:结果是一个Composed实例,其中包含按要求将左参数重复多次。

Composable.as_bytes()

abstract as_bytes(context: Optional[AdaptContext])  bytes

以字节形式返回对象的值。

参数:

context (connectioncursor) – 处理对象的上下文。

如果传递的是Composable而不是查询字符串,该方法会由 execute(), executemany(), copy()自动调用。

Composable.as_string()

as_string(context: Optional[AdaptContext])  str

将对象的值作为字符串返回。

参数:

context (connectioncursor) – 处理字符串的上下文。

SQL 类

class psycopg.sql.SQL(obj: LiteralString)

表示 SQL 语句片段的Composable

SQL公开的join()format()方法可用于创建模板,在模板中合并查询的可变部分(例如字段名或表名)。

字符串obj不进行任何形式的转义,因此它不适合表示变量标识符或值:您应该只用它来传递表示模板或 SQL 语句片段的常量字符串;使用其他对象如IdentifierLiteral来表示可变部分。

例子:

>>> query = sql.SQL("SELECT {0} FROM {1}").format(
...    sql.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]),
...    sql.Identifier('table'))
>>> print(query.as_string(conn))
SELECT "foo", "bar" FROM "table"

在 3.1 版更改: 输入对象应该是一个LiteralString。有关详细信息,请参阅 PEP 675

SQL.format()

format(*args: Any, **kwargs: Any)  Composed

Composable对象合并到模板中。

参数:

  • args – 替换为编号 ({0}, {1}) 或自动编号 ({}) 占位符的参数
  • kwargs – 替换为命名 ({name}) 占位符的参数

返回:

SQL字符串中的占位符使用参数值替换后的组合字符串

返回类型:

Composed

该方法类似于 Python 提供的str.format()方法:字符串模板支持自动编号 ({})、编号 ({0}, {1}…) 和命名占位符 ({name}),用位置参数替换编号占位符,用关键字替换命名占位符。但是,不支持占位符修饰符 ({0!r}, {0:<10})。

如果将Composable对象传递给模板,它将根据其as_string()方法进行合并。如果传递任何其他 Python 对象,它将被包装在一个Literal对象中,因此会根据 SQL 规则进行转义。

例子:

>>> print(sql.SQL("SELECT * FROM {} WHERE {} = %s")
...     .format(sql.Identifier('people'), sql.Identifier('id'))
...     .as_string(conn))
SELECT * FROM "people" WHERE "id" = %s

>>> print(sql.SQL("SELECT * FROM {tbl} WHERE name = {name}")
...     .format(tbl=sql.Identifier('people'), name="O'Rourke"))
...     .as_string(conn))
SELECT * FROM "people" WHERE name = 'O''Rourke'

SQL.join()

join(seq: Iterable[Composable])  Composed

连接Composable对象序列。

参数:

seq (可迭代的Composable) – 要连接的元素。

使用SQL对象的字符串来分隔seq。请注意,Composed对象也是可迭代的,因此它们可以用作此方法的参数。

例子:

>>> snip = sql.SQL(', ').join(
...     sql.Identifier(n) for n in ['foo', 'bar', 'baz'])
>>> print(snip.as_string(conn))
"foo", "bar", "baz"

Identifier 类

class psycopg.sql.Identifier(*strings: str)

表示 SQL 标识符或点号分隔的标识符序列的Composable

标识符通常表示数据库对象的名称,例如表或字段。PostgreSQL 标识符遵循与 SQL 字符串文字不同的转义规则(例如,它们使用双引号而不是单引号)。

例子:

>>> t1 = sql.Identifier("foo")
>>> t2 = sql.Identifier("ba'r")
>>> t3 = sql.Identifier('ba"z')
>>> print(sql.SQL(', ').join([t1, t2, t3]).as_string(conn))
"foo", "ba'r", "ba""z"

可以将多个字符串传递给对象以表示限定名称,即以点号分隔的标识符序列。

例子:

>>> query = sql.SQL("SELECT {} FROM {}").format(
...     sql.Identifier("table", "field"),
...     sql.Identifier("schema", "table"))
>>> print(query.as_string(conn))
SELECT "table"."field" FROM "schema"."table"

Literal 类

class psycopg.sql.Literal(obj: Any)

表示要包含在查询中的 SQL 值的Composable

通常您会希望在查询中包含占位符并将值作为参数传递给execute()。但是,如果您确实确实需要在查询中包含文字值,则可以使用此对象。

使用as_string()返回的字符串遵循 Python 对象的正常适配规则

例子:

>>> s1 = sql.Literal("fo'o")
>>> s2 = sql.Literal(42)
>>> s3 = sql.Literal(date(2000, 1, 1))
>>> print(sql.SQL(', ').join([s1, s2, s3]).as_string(conn))
'fo''o', 42, '2000-01-01'::date

*在 3.1 版更改:*如果在不明确的上下文中有用,则向表示添加类型转换(例如'2000-01-01'::date)。

Placeholder 类

class psycopg.sql.Placeholder(name: str = '', format: Union[str, PyFormat] = PyFormat.AUTO)

表示查询参数的占位符的Composable

如果指定了名称,则生成命名占位符(例如%(name)s, %(name)b),否则生成位置占位符(例如%s, %b)。

该对象可用于生成具有可变数量参数的 SQL 查询。

例子:

>>> names = ['foo', 'bar', 'baz']

>>> q1 = sql.SQL("INSERT INTO my_table ({}) VALUES ({})").format(
...     sql.SQL(', ').join(map(sql.Identifier, names)),
...     sql.SQL(', ').join(sql.Placeholder() * len(names)))
>>> print(q1.as_string(conn))
INSERT INTO my_table ("foo", "bar", "baz") VALUES (%s, %s, %s)

>>> q2 = sql.SQL("INSERT INTO my_table ({}) VALUES ({})").format(
...     sql.SQL(', ').join(map(sql.Identifier, names)),
...     sql.SQL(', ').join(map(sql.Placeholder, names)))
>>> print(q2.as_string(conn))
INSERT INTO my_table ("foo", "bar", "baz") VALUES (%(foo)s, %(bar)s, %(baz)s)

Composed 类

class psycopg.sql.Composed(seq: Sequence[Any])

Composable序列组成的Composable对象。

通常使用Composable的运算符和方法创建该对象。然而,也可以直接指定一系列对象作为参数创建一个Composed的对象:如果它们不是Composable,它们将被包装成一个Literal

例子:

>>> comp = sql.Composed(
...     [sql.SQL("INSERT INTO "), sql.Identifier("table")])
>>> print(comp.as_string(conn))
INSERT INTO "table"

Composed对象是可迭代的(因此它们可以用在SQL.join这样的方法)。

Composed.join()

join(joiner: Union[SQL, LiteralString])  Composed

joiner插入Composed项之间,返回一个新的Composed

joiner必须是一个SQL或将被解释为SQL的字符串。

例子:

>>> fields = sql.Identifier('foo') + sql.Identifier('bar')  # a Composed
>>> print(fields.join(', ').as_string(conn))
"foo", "bar"

工具函数

quote()

psycopg.sql.quote(obj: Any, context: Optional[AdaptContext] = None)  str

适配 Python 对象到带引号的 SQL 字符串。

仅当您绝对想将 Python 字符串转换为带引号的 SQL 文字以用于生成批处理 SQL 时才使用此函数,并且当您需要使用它时您还没有可用的连接。

这个函数效率比较低,因为它不缓存适配规则。如果你传递一个context,你可以调整使用的适配规则,否则会使用全局的规则。

NULL

psycopg.sql.NULL

经常用在查询中的sql.SQL对象。

DEFAULT

psycopg.sql.DEFAULT

经常用在查询中的sql.SQL对象。