操作符参考

本节详细介绍了可用于构建 SQL 表达式的操作符的使用方法。

这些方法以 OperatorsColumnOperators 基类表示。这些方法在这些类的子类中可用,包括

这些操作符首先在教程部分介绍,包括

比较操作符

适用于许多数据类型的基本比较,包括数值、字符串、日期和许多其他类型

IN 比较

SQL 的 IN 操作符在 SQLAlchemy 中是一个独立的主题。由于 IN 操作符通常针对固定值的列表使用,所以 SQLAlchemy 的绑定参数强制转换功能使用了一种特殊的 SQL 编译形式,该形式在编译时生成一个中间 SQL 字符串,该字符串在第二步中被转换为最终的绑定参数列表。换句话说,“它只是有效”。

对值列表进行 IN 比较

IN 通常通过将值列表传递给 ColumnOperators.in_() 方法来使用。

>>> print(column("x").in_([1, 2, 3]))
x IN (__[POSTCOMPILE_x_1])

特殊的绑定形式 __[POSTCOMPILE 会在执行时渲染为单个参数,如下所示。

>>> stmt = select(User.id).where(User.id.in_([1, 2, 3]))
>>> result = conn.execute(stmt)
SELECT user_account.id FROM user_account WHERE user_account.id IN (?, ?, ?) [...] (1, 2, 3)

空 IN 表达式

SQLAlchemy 通过渲染一个返回没有行的特定于后端的子查询来生成一个数学上有效的空 IN 表达式的结果。同样,换句话说,“它只是有效”。

>>> stmt = select(User.id).where(User.id.in_([]))
>>> result = conn.execute(stmt)
SELECT user_account.id FROM user_account WHERE user_account.id IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1) [...] ()

上面的“空集”子查询正确地概括了,并且也根据 IN 操作符渲染,该操作符仍然保留在位。

NOT IN

“NOT IN” 通过 ColumnOperators.not_in() 操作符提供。

>>> print(column("x").not_in([1, 2, 3]))
(x NOT IN (__[POSTCOMPILE_x_1]))

这通常可以通过对 ~ 运算符进行否定来更容易地获得。

>>> print(~column("x").in_([1, 2, 3]))
(x NOT IN (__[POSTCOMPILE_x_1]))

元组 IN 表达式

元组与元组的比较在 IN 中很常见,因为它除了其他用例外,还可以适应将行与一组可能的复合主键值进行匹配的情况。 tuple_() 构造提供了元组比较的基本构建块。然后,Tuple.in_() 操作符接收一个元组列表。

>>> from sqlalchemy import tuple_
>>> tup = tuple_(column("x", Integer), column("y", Integer))
>>> expr = tup.in_([(1, 2), (3, 4)])
>>> print(expr)
(x, y) IN (__[POSTCOMPILE_param_1])

为了说明渲染的参数。

>>> tup = tuple_(User.id, Address.id)
>>> stmt = select(User.name).join(Address).where(tup.in_([(1, 1), (2, 2)]))
>>> conn.execute(stmt).all()
SELECT user_account.name FROM user_account JOIN address ON user_account.id = address.user_id WHERE (user_account.id, address.id) IN (VALUES (?, ?), (?, ?)) [...] (1, 1, 2, 2)
[('spongebob',), ('sandy',)]

子查询 IN

最后,ColumnOperators.in_()ColumnOperators.not_in() 操作符适用于子查询。该形式规定直接传递一个 Select 构造,无需将其显式转换为命名子查询。

>>> print(column("x").in_(select(user_table.c.id)))
x IN (SELECT user_account.id FROM user_account)

元组按预期工作。

>>> print(
...     tuple_(column("x"), column("y")).in_(
...         select(user_table.c.id, address_table.c.id).join(address_table)
...     )
... )
(x, y) IN (SELECT user_account.id, address.id FROM user_account JOIN address ON user_account.id = address.user_id)

身份比较

这些操作符涉及测试特殊的 SQL 值,例如 NULL、布尔常量,例如 truefalse,某些数据库支持这些值。

  • ColumnOperators.is_():

    此操作符将提供 “x IS y” 的 SQL,最常被看作是 “<expr> IS NULL”。 NULL 常量通常使用 Python 的 None 获取。

    >>> print(column("x").is_(None))
    
    x IS NULL

    如果需要,可以使用 null() 构造显式地获取 SQL NULL。

    >>> from sqlalchemy import null
    >>> print(column("x").is_(null()))
    
    x IS NULL

    当与 Nonenull() 值一起使用时,ColumnOperators.is_() 操作符会自动调用,即 ColumnOperators.__eq__() 重载运算符,即 ==。这样,通常不需要显式使用 ColumnOperators.is_(),特别是当与动态值一起使用时。

    >>> a = None
    >>> print(column("x") == a)
    
    x IS NULL

    请注意,Python 的 is 运算符**没有重载**。即使 Python 提供了重载运算符(如 ==!=)的钩子,它**也不**提供任何重新定义 is 的方法。

  • ColumnOperators.is_not():

    类似于 ColumnOperators.is_(),生成“IS NOT”

    >>> print(column("x").is_not(None))
    
    x IS NOT NULL

    类似于 != None

    >>> print(column("x") != None)
    
    x IS NOT NULL
  • ColumnOperators.is_distinct_from():

    生成 SQL IS DISTINCT FROM

    >>> print(column("x").is_distinct_from("some value"))
    
    x IS DISTINCT FROM :x_1
  • ColumnOperators.isnot_distinct_from():

    生成 SQL IS NOT DISTINCT FROM

    >>> print(column("x").isnot_distinct_from("some value"))
    
    x IS NOT DISTINCT FROM :x_1

字符串比较

字符串包含

字符串包含运算符基本上是作为 LIKE 和字符串连接运算符的组合构建的,在大多数后端上是 ||,或者有时是像 concat() 这样的函数

字符串匹配

匹配运算符总是特定于后端的,并且可能在不同的数据库上提供不同的行为和结果

  • ColumnOperators.match():

    这是一个特定于方言的运算符,它使用底层数据库(如果可用)的 MATCH 功能

    >>> print(column("x").match("word"))
    
    x MATCH :x_1
  • ColumnOperators.regexp_match():

    此运算符特定于方言。我们可以用 PostgreSQL 方言为例来说明它

    >>> from sqlalchemy.dialects import postgresql
    >>> print(column("x").regexp_match("word").compile(dialect=postgresql.dialect()))
    
    x ~ %(x_1)s

    或 MySQL

    >>> from sqlalchemy.dialects import mysql
    >>> print(column("x").regexp_match("word").compile(dialect=mysql.dialect()))
    
    x REGEXP %s

字符串修改

  • ColumnOperators.concat():

    字符串连接

    >>> print(column("x").concat("some string"))
    
    x || :x_1

    此运算符可通过 ColumnOperators.__add__() 获得,即在处理从 String 派生的列表达式时使用 Python + 运算符。

    >>> print(column("x", String) + "some string")
    
    x || :x_1

    此运算符将生成适当的特定于数据库的结构,例如在 MySQL 上,它历史上一直是 concat() SQL 函数

    >>> print((column("x", String) + "some string").compile(dialect=mysql.dialect()))
    
    concat(x, %s)
  • ColumnOperators.regexp_replace():

    作为 ColumnOperators.regexp() 的补充,它为支持它的后端生成 REGEXP REPLACE 等效项

    >>> print(column("x").regexp_replace("foo", "bar").compile(dialect=postgresql.dialect()))
    
    REGEXP_REPLACE(x, %(x_1)s, %(x_2)s)
  • ColumnOperators.collate():

    生成 COLLATE SQL 运算符,该运算符在表达式时提供特定整理

    >>> print(
    ...     (column("x").collate("latin1_german2_ci") == "Müller").compile(
    ...         dialect=mysql.dialect()
    ...     )
    ... )
    
    (x COLLATE latin1_german2_ci) = %s

    要对文字值使用 COLLATE,请使用 literal() 结构

    >>> from sqlalchemy import literal
    >>> print(
    ...     (literal("Müller").collate("latin1_german2_ci") == column("x")).compile(
    ...         dialect=mysql.dialect()
    ...     )
    ... )
    
    (%s COLLATE latin1_german2_ci) = x

算术运算符

按位运算符

按位运算符函数提供跨不同后端统一访问按位运算符,这些运算符预计对兼容值(如整数和位字符串(例如 PostgreSQL BIT 等))起作用。请注意,这些**不是**一般的布尔运算符。

在版本 2.0.2 中新增: 添加了用于按位运算的专用运算符。

  • ColumnOperators.bitwise_not()bitwise_not()。作为列级方法提供,对父对象生成按位 NOT 子句

    >>> print(column("x").bitwise_not())
    ~x

    此运算符也可以作为列表达式级方法提供,对单个列表达式应用按位 NOT

    >>> from sqlalchemy import bitwise_not
    >>> print(bitwise_not(column("x")))
    ~x
  • ColumnOperators.bitwise_and() 生成按位 AND

    >>> print(column("x").bitwise_and(5))
    x & :x_1
  • ColumnOperators.bitwise_or() 生成按位 OR

    >>> print(column("x").bitwise_or(5))
    x | :x_1
  • ColumnOperators.bitwise_xor() 生成按位 XOR

    >>> print(column("x").bitwise_xor(5))
    x ^ :x_1

    对于 PostgreSQL 方言,使用“#”表示按位 XOR;在使用这些后端之一时,它会自动发出

    >>> from sqlalchemy.dialects import postgresql
    >>> print(column("x").bitwise_xor(5).compile(dialect=postgresql.dialect()))
    x # %(x_1)s
  • ColumnOperators.bitwise_rshift()ColumnOperators.bitwise_lshift() 生成按位移位运算符

    >>> print(column("x").bitwise_rshift(5))
    x >> :x_1
    >>> print(column("x").bitwise_lshift(5))
    x << :x_1

使用连接和否定

最常见的连接“AND”会在我们多次使用 Select.where() 方法时自动应用,以及类似的方法(如 Update.where()Delete.where()

>>> print(
...     select(address_table.c.email_address)
...     .where(user_table.c.name == "squidward")
...     .where(address_table.c.user_id == user_table.c.id)
... )
SELECT address.email_address FROM address, user_account WHERE user_account.name = :name_1 AND address.user_id = user_account.id

Select.where()Update.where()Delete.where() 也接受多个表达式,效果相同。

>>> print(
...     select(address_table.c.email_address).where(
...         user_table.c.name == "squidward",
...         address_table.c.user_id == user_table.c.id,
...     )
... )
SELECT address.email_address FROM address, user_account WHERE user_account.name = :name_1 AND address.user_id = user_account.id

“AND” 连接词及其对应的 “OR” 连接词都可以直接使用 and_()or_() 函数。

>>> from sqlalchemy import and_, or_
>>> print(
...     select(address_table.c.email_address).where(
...         and_(
...             or_(user_table.c.name == "squidward", user_table.c.name == "sandy"),
...             address_table.c.user_id == user_table.c.id,
...         )
...     )
... )
SELECT address.email_address FROM address, user_account WHERE (user_account.name = :name_1 OR user_account.name = :name_2) AND address.user_id = user_account.id

可以使用 not_() 函数进行否定。这通常会反转布尔表达式中的操作符。

>>> from sqlalchemy import not_
>>> print(not_(column("x") == 5))
x != :x_1

它也可能在适当的时候应用 NOT 这样的关键字。

>>> from sqlalchemy import Boolean
>>> print(not_(column("x", Boolean)))
NOT x

连接操作符

上述连接函数 and_()or_()not_() 也以重载的 Python 操作符的形式提供。

注意

Python 的 &|~ 操作符在语言中具有很高的优先级;因此,对于本身包含表达式的操作数,通常必须应用括号,如下面的示例所示。

  • Operators.__and__() (Python 的 “&” 操作符)

    Python 二元 & 操作符被重载以与 and_() 行为相同(请注意两个操作数周围的括号)。

    >>> print((column("x") == 5) & (column("y") == 10))
    
    x = :x_1 AND y = :y_1
  • Operators.__or__() (Python 的 “|” 操作符)

    Python 二元 | 操作符被重载以与 or_() 行为相同(请注意两个操作数周围的括号)。

    >>> print((column("x") == 5) | (column("y") == 10))
    
    x = :x_1 OR y = :y_1
  • Operators.__invert__() (Python 的 “~” 操作符)

    Python 二元 ~ 操作符被重载以与 not_() 行为相同,要么反转现有的操作符,要么将 NOT 关键字应用于整个表达式。

    >>> print(~(column("x") == 5))
    
    x != :x_1
    >>> from sqlalchemy import Boolean >>> print(~column("x", Boolean))
    NOT x