SqlAlchemy 2.0 中文文档(三十五)(1)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: SqlAlchemy 2.0 中文文档(三十五)


原文:docs.sqlalchemy.org/en/20/contents.html

运算符参考

原文:docs.sqlalchemy.org/en/20/core/operators.html

本节详细介绍了用于构建 SQL 表达式的运算符的用法。

这些方法按照 OperatorsColumnOperators 基类的方式呈现。然后这些方法可用于这些类的后代,包括:

  • Column 对象
  • ColumnElement 对象更一般地,这些对象是所有 Core SQL 表达式语言列级表达式的根
  • InstrumentedAttribute 对象,这些对象是 ORM 级别的映射属性。

运算符首先在教程部分中介绍,包括:

  • SQLAlchemy 统一教程 - 以 2.0 风格 呈现的统一教程
  • 对象关系教程 - ORM 教程以 1.x 风格 呈现
  • SQL 表达式语言教程 - 以 1.x 风格 呈现的核心教程

比较运算符

基本比较,适用于许多数据类型,包括数值、字符串、日期等:

  • ColumnOperators.__eq__() (Python “==” 运算符):
>>> print(column("x") == 5)
x  =  :x_1 
  • ColumnOperators.__ne__() (Python “!=” 运算符):
>>> print(column("x") != 5)
x  !=  :x_1 
  • ColumnOperators.__gt__() (Python “>” 运算符):
>>> print(column("x") > 5)
x  >  :x_1 
  • ColumnOperators.__lt__() (Python “<” 运算符):
>>> print(column("x") < 5)
x  <  :x_1 
  • ColumnOperators.__ge__() (Python “>=” 运算符):
>>> print(column("x") >= 5)
x  >=  :x_1 
  • ColumnOperators.__le__() (Python “<=” 运算符):
>>> print(column("x") <= 5)
x  <=  :x_1 
  • ColumnOperators.between()
>>> print(column("x").between(5, 10))
x  BETWEEN  :x_1  AND  :x_2 

IN 比较

SQL IN 运算符是 SQLAlchemy 中的一个主题。 由于 IN 运算符通常针对一组固定值使用,因此 SQLAlchemy  的绑定参数 coercion 功能利用了特殊形式的 SQL 编译,将中间 SQL 字符串渲染为最终绑定参数列表,然后在第二步形成。  换句话说,“它只是工作”。

针对一组值的 IN

通常通过将值列表传递给 ColumnOperators.in_() 方法来实现 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,最常见的是“ IS NULL”。 使用常规 Python None 最容易获得NULL 常量:
>>> print(column("x").is_(None))
x  IS  NULL 
  • 如果需要,SQL NULL 也可以显式使用null() 构造:
>>> from sqlalchemy import null
>>> print(column("x").is_(null()))
x  IS  NULL 
  • 当使用ColumnOperators.__eq__()重载运算符,即==,与Nonenull()值一起使用时,ColumnOperators.is_()运算符会自动调用。因此,通常不需要显式使用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 

字符串比较:

  • ColumnOperators.like()
>>> print(column("x").like("word"))
x  LIKE  :x_1 
  • ColumnOperators.ilike()
    大小写不敏感的 LIKE 使用通用后端上的 SQL lower()函数。在 PostgreSQL 后端上,它将使用ILIKE
>>> print(column("x").ilike("word"))
lower(x)  LIKE  lower(:x_1) 
  • ColumnOperators.notlike()
>>> print(column("x").notlike("word"))
x  NOT  LIKE  :x_1 
  • ColumnOperators.notilike()
>>> print(column("x").notilike("word"))
lower(x)  NOT  LIKE  lower(:x_1) 

字符串包含:

字符串包含运算符基本上是由 LIKE 和字符串连接运算符组合而成,大多数后端使用||,有时候也会使用像concat()这样的函数:

  • ColumnOperators.startswith()
>>> print(column("x").startswith("word"))
x  LIKE  :x_1  ||  '%' 
  • ColumnOperators.endswith()
>>> print(column("x").endswith("word"))
x  LIKE  '%'  ||  :x_1 
  • ColumnOperators.contains()
>>> print(column("x").contains("word"))
x  LIKE  '%'  ||  :x_1  ||  '%' 

字符串匹配

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

  • 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 

算术运算符

  • ColumnOperators.__add__()ColumnOperators.__radd__()(Python “+” 运算符):
>>> print(column("x") + 5)
x  +  :x_1
>>> print(5 + column("x"))
:x_1  +  x 
  • 请注意,当表达式的数据类型是 String 或类似类型时,ColumnOperators.__add__() 运算符会产生 字符串连接:
  • ColumnOperators.__sub__(), ColumnOperators.__rsub__() (Python “-” 运算符):
>>> print(column("x") - 5)
x  -  :x_1
>>> print(5 - column("x"))
:x_1  -  x 
  • ColumnOperators.__mul__(), ColumnOperators.__rmul__() (Python “*” 运算符):
>>> print(column("x") * 5)
x  *  :x_1
>>> print(5 * column("x"))
:x_1  *  x 
  • ColumnOperators.__truediv__(), ColumnOperators.__rtruediv__() (Python “/” 运算符)。这是 Python 的 truediv 运算符,它将确保进行整数真除法:
>>> print(column("x") / 5)
x  /  CAST(:x_1  AS  NUMERIC)
>>> print(5 / column("x"))
:x_1  /  CAST(x  AS  NUMERIC) 
  • 从版本 2.0 起更改:Python 的 / 运算符现在确保进行整数真除法。
  • ColumnOperators.__floordiv__(), ColumnOperators.__rfloordiv__() (Python “//” 运算符)。这是 Python 的 floordiv 运算符,它将确保进行地板除法。对于默认后端以及诸如 PostgreSQL 之类的后端,SQL / 运算符通常以这种方式处理整数值:
>>> print(column("x") // 5)
x  /  :x_1
>>> print(5 // column("x", Integer))
:x_1  /  x 
  • 对于默认不使用地板除法的后端,或者当与数字值一起使用时,使用 FLOOR() 函数以确保地板除法:
>>> print(column("x") // 5.5)
FLOOR(x  /  :x_1)
>>> print(5 // column("x", Numeric))
FLOOR(:x_1  /  x) 
  • 版本 2.0 中新增:支持地板除法
  • ColumnOperators.__mod__(), ColumnOperators.__rmod__() (Python “%” 运算符):
>>> print(column("x") % 5)
x  %  :x_1
>>> print(5 % column("x"))
:x_1  %  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() 产生按位与:
>>> print(column("x").bitwise_and(5))
x & :x_1
  • ColumnOperators.bitwise_or() 产生按位或:
>>> print(column("x").bitwise_or(5))
x | :x_1
  • ColumnOperators.bitwise_xor() 产生按位异或:
>>> print(column("x").bitwise_xor(5))
x ^ :x_1
  • 对于 PostgreSQL 方言,“#” 被用来表示按位异或;当使用这些后端之一时,它会自动发出:
>>> 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 “&” operator):
    Python 二进制&运算符被重载,以与and_() 相同(请注意两个操作数周围的括号):
>>> print((column("x") == 5) & (column("y") == 10))
x  =  :x_1  AND  y  =  :y_1 
  • Operators.__or__() (Python “|” operator):
    Python 二进制|运算符被重载,以与or_() 相同(请注意两个操作数周围的括号):
>>> print((column("x") == 5) | (column("y") == 10))
x  =  :x_1  OR  y  =  :y_1 
  • Operators.__invert__() (Python “~” operator):
    Python 二进制~运算符被重载,以与not_() 相同,可以反转现有运算符,或将NOT关键字应用于整个表达式:
>>> print(~(column("x") == 5))
x  !=  :x_1
>>> from sqlalchemy import Boolean
>>> print(~column("x", Boolean))
NOT  x 

比较运算符

基本比较适用于许多数据类型,包括数字、字符串、日期等:

  • ColumnOperators.__eq__() (Python “==” operator):
>>> print(column("x") == 5)
x  =  :x_1 
  • ColumnOperators.__ne__() (Python “!=” operator):
>>> print(column("x") != 5)
x  !=  :x_1 
  • ColumnOperators.__gt__() (Python “>” operator):
>>> print(column("x") > 5)
x  >  :x_1 
  • ColumnOperators.__lt__() (Python “<” operator):
>>> print(column("x") < 5)
x  <  :x_1 
  • ColumnOperators.__ge__() (Python “>=” operator):
>>> print(column("x") >= 5)
x  >=  :x_1 
  • ColumnOperators.__le__() (Python “<=” operator):
>>> print(column("x") <= 5)
x  <=  :x_1 
  • ColumnOperators.between():
>>> print(column("x").between(5, 10))
x  BETWEEN  :x_1  AND  :x_2 

IN 比较

SQL 的 IN 操作符在 SQLAlchemy 中是一个单独的主题。由于 IN 操作符通常针对一组固定值使用,SQLAlchemy 的绑定参数强制转换特性利用一种特殊形式的 SQL 编译,在第二步形成最终的绑定参数列表。换句话说,“它就是这样工作”。

针对值列表的 IN

通过将值列表传递给 ColumnOperators.in_() 方法,通常可以使用 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) 

针对值列表的 IN

通过将值列表传递给 ColumnOperators.in_() 方法,通常可以使用 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,通常表示为“ IS NULL”。使用常规的 Python None 最容易获得NULL 常量:
>>> print(column("x").is_(None))
x  IS  NULL 
  • 如果需要,SQL NULL 也可以明确使用null() 构造获得:
>>> from sqlalchemy import null
>>> print(column("x").is_(null()))
x  IS  NULL 
  • 当使用ColumnOperators.__eq__() 重载的操作符,即==,与Nonenull()值一起使用时,ColumnOperators.is_() 操作符会自动调用。因此,通常不需要显式使用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 

字符串比较

  • ColumnOperators.like():
>>> print(column("x").like("word"))
x  LIKE  :x_1 
  • ColumnOperators.ilike():
    不区分大小写的 LIKE 在通用后端上使用 SQL lower() 函数。在 PostgreSQL 后端上,它将使用 ILIKE
>>> print(column("x").ilike("word"))
lower(x)  LIKE  lower(:x_1) 
  • ColumnOperators.notlike():
>>> print(column("x").notlike("word"))
x  NOT  LIKE  :x_1 
  • ColumnOperators.notilike():
>>> print(column("x").notilike("word"))
lower(x)  NOT  LIKE  lower(:x_1) 

字符串包含

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

  • ColumnOperators.startswith():
>>> print(column("x").startswith("word"))
x  LIKE  :x_1  ||  '%' 
  • ColumnOperators.endswith():
>>> print(column("x").endswith("word"))
x  LIKE  '%'  ||  :x_1 
  • ColumnOperators.contains():
>>> print(column("x").contains("word"))
x  LIKE  '%'  ||  :x_1  ||  '%' 

字符串匹配

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

  • 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 
  • 当使用从 String 派生的列表达式时,此运算符可通过 ColumnOperators.__add__() 提供,即 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 

算术运算符

  • ColumnOperators.__add__()ColumnOperators.__radd__()(Python “+” 运算符):
>>> print(column("x") + 5)
x  +  :x_1
>>> print(5 + column("x"))
:x_1  +  x 
  • 请注意,当表达式的数据类型是 String 或类似时,ColumnOperators.__add__() 运算符会产生字符串连接而不是 字符串连接:
  • ColumnOperators.__sub__()ColumnOperators.__rsub__()(Python “-” 运算符):
>>> print(column("x") - 5)
x  -  :x_1
>>> print(5 - column("x"))
:x_1  -  x 
  • ColumnOperators.__mul__()ColumnOperators.__rmul__()(Python “*” 运算符):
>>> print(column("x") * 5)
x  *  :x_1
>>> print(5 * column("x"))
:x_1  *  x 
  • ColumnOperators.__truediv__(), ColumnOperators.__rtruediv__()(Python “/” 运算符)。这是 Python 的 truediv 运算符,它确保进行整数真除法:
>>> print(column("x") / 5)
x  /  CAST(:x_1  AS  NUMERIC)
>>> print(5 / column("x"))
:x_1  /  CAST(x  AS  NUMERIC) 
  • 在 2.0 版本中更改:Python / 运算符现在确保进行整数真除法
  • ColumnOperators.__floordiv__(), ColumnOperators.__rfloordiv__()(Python “//” 运算符)。这是 Python 的 floordiv 运算符,它确保进行 floor division。对于默认后端以及诸如 PostgreSQL 这样的后端,SQL / 运算符通常以这种方式对整数值进行操作:
>>> print(column("x") // 5)
x  /  :x_1
>>> print(5 // column("x", Integer))
:x_1  /  x 
  • 对于默认不使用 floor division 的后端,或者与数值一起使用时,使用 FLOOR() 函数来确保进行 floor division:
>>> print(column("x") // 5.5)
FLOOR(x  /  :x_1)
>>> print(5 // column("x", Numeric))
FLOOR(:x_1  /  x) 
  • 2.0 版本中的新功能:支持 FLOOR division
  • ColumnOperators.__mod__(), ColumnOperators.__rmod__()(Python “%” 运算符):
>>> print(column("x") % 5)
x  %  :x_1
>>> print(5 % column("x"))
:x_1  %  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() 产生按位与:
>>> 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() 产生按位异或操作符:
>>> print(column("x").bitwise_xor(5))
x ^ :x_1
  • 对于 PostgreSQL 方言,“#” 用于表示按位异或;在使用其中一个后端时会自动发出:
>>> 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

使用连接词和否定

如果我们反复使用 Select.where() 方法,以及类似的方法如 Update.where()Delete.where(),最常见的连接词“AND”会自动应用:

>>> 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 “|” operator):
    Python 的二进制|运算符被重载,以与or_()(注意两个操作数周围的括号)行为相同:
>>> print((column("x") == 5) | (column("y") == 10))
x  =  :x_1  OR  y  =  :y_1 
  • Operators.__invert__() (Python “~” operator):
    Python 的二进制~运算符被重载,以与not_()行为相同,可以反转现有运算符,或将NOT关键字应用于整个表达式:
>>> print(~(column("x") == 5))
x  !=  :x_1
>>> from sqlalchemy import Boolean
>>> print(~column("x", Boolean))
NOT  x 

SELECT 及相关构造

原文:docs.sqlalchemy.org/en/20/core/selectable.html

术语“可选择的”指代任何代表数据库行的对象。在 SQLAlchemy 中,这些对象都是 Selectable 的子类,其中最突出的是 Select,它表示一个 SQL SELECT 语句。Selectable 的一个子集是 FromClause,它表示可以在 Select 语句的 FROM 子句中的对象。FromClause 的一个区别性特征是 FromClause.c 属性,它是 FROM 子句中包含的所有列的命名空间(这些元素本身是 ColumnElement 的子类)。

可选择的基本构造

最高级的“FROM 子句”和“SELECT”构造器。

对象名称 描述
except_(*selects) 返回多个可选项的 EXCEPT
except_all(*selects) 返回多个可选项的 EXCEPT ALL
exists([__argument]) 构造一个新的 Exists 构造。
intersect(*selects) 返回多个可选项的 INTERSECT
intersect_all(*selects) 返回多个可选项的 INTERSECT ALL
select(*entities, **__kw) 构造一个新的 Select
table(name, *columns, **kw) 生成一个新的 TableClause
union(*selects) 返回多个可选项的 UNION
union_all(*selects) 返回多个可选项的 UNION ALL
values(*columns, [name, literal_binds]) 构造一个 Values 构造。
function sqlalchemy.sql.expression.except_(*selects: _SelectStatementForCompoundArgument) → CompoundSelect

返回多个可选项的 EXCEPT

返回的对象是一个CompoundSelect的实例。

参数:

*selects – 一个Select实例的列表。

function sqlalchemy.sql.expression.except_all(*selects: _SelectStatementForCompoundArgument) → CompoundSelect

返回多个可选择的EXCEPT ALL

返回的对象是一个CompoundSelect的实例。

参数:

*selects – 一个Select实例的列表。

function sqlalchemy.sql.expression.exists(__argument: _ColumnsClauseArgument[Any] | SelectBase | ScalarSelect[Any] | None = None) → Exists

构建一个新的Exists构造。

exists()可以单独调用以生成一个Exists构造,该构造将接受简单的 WHERE 条件:

exists_criteria = exists().where(table1.c.col1 == table2.c.col2)

然而,为了在构建 SELECT 时具有更大的灵活性,可以将现有的Select构造转换为Exists,最方便的方法是利用SelectBase.exists()方法:

exists_criteria = (
    select(table2.c.col2).
    where(table1.c.col1 == table2.c.col2).
    exists()
)

EXISTS 条件然后在封闭的 SELECT 中使用:

stmt = select(table1.c.col1).where(exists_criteria)

上述语句将如下形式:

SELECT col1 FROM table1 WHERE EXISTS
(SELECT table2.col2 FROM table2 WHERE table2.col2 = table1.col1)

另请参阅

EXISTS 子查询 - 在 2.0 风格教程中。

SelectBase.exists() - 将SELECT转换为EXISTS子句的方法。

function sqlalchemy.sql.expression.intersect(*selects: _SelectStatementForCompoundArgument) → CompoundSelect

返回多个可选择的INTERSECT

返回的对象是一个CompoundSelect的实例。

参数:

*selects – 一个Select实例的列表。

function sqlalchemy.sql.expression.intersect_all(*selects: _SelectStatementForCompoundArgument) → CompoundSelect

返回多个可选择的INTERSECT ALL

返回的对象是一个CompoundSelect的实例。

参数:

*selects – 一个Select实例的列表。

function sqlalchemy.sql.expression.select(*entities: _ColumnsClauseArgument[Any], **__kw: Any) → Select[Any]

构建一个新的Select

新版本 1.4 中:- select()函数现在可以按位置接受列参数。顶层的select()函数将根据传入的参数自动使用 1.x 或 2.x 风格的 API;使用来自sqlalchemy.future模块的select()将强制使用仅使用 2.x 风格的构造函数。

类似的功能也可通过任何FromClause上的FromClause.select()方法获得。

另请参阅

使用 SELECT 语句 - 在 SQLAlchemy 统一教程中

参数:

*entities

要从中选择的实体。对于核心用法,这通常是一系列将形成结果语句的列子句的ColumnElement和/或FromClause对象。对于那些是FromClause的实例的对象(通常是TableAlias对象),FromClause.c 集合被提取出来形成ColumnElement对象的集合。

此参数还将接受TextClause构造,以及 ORM 映射的类。

function sqlalchemy.sql.expression.table(name: str, *columns: ColumnClause[Any], **kw: Any) → TableClause

创建一个新的TableClause

返回的对象是TableClause的一个实例,它表示架构级别的Table对象的“句法”部分。它可用于构建轻量级的表构造。

参数:

  • name – 表的名称。
  • columns – 一个column() 构造的集合。
  • schema
    此表的架构名称。
    新版本 1.3.18 中:table()现在可以接受一个schema参数。
function sqlalchemy.sql.expression.union(*selects: _SelectStatementForCompoundArgument) → CompoundSelect

返回多个可选择的UNION

返回的对象是CompoundSelect的一个实例。

所有FromClause子类上都有一个类似的union()方法。

参数:

  • *selects – 一个Select实例列表。
  • **kwargs – 可用的关键字参数与select()的相同。
function sqlalchemy.sql.expression.union_all(*selects: _SelectStatementForCompoundArgument) → CompoundSelect

返回多个可选择的UNION ALL

返回的对象是CompoundSelect的一个实例。

所有FromClause子类上都有一个类似的union_all()方法。

参数:

*selects – 一个Select实例列表。

function sqlalchemy.sql.expression.values(*columns: ColumnClause[Any], name: str | None = None, literal_binds: bool = False) → Values

构建一个Values构造。

列表达式和Values的实际数据在两个独立的步骤中给出。构造函数通常接收列表达式,通常作为column()构造,并且数据通过Values.data()方法传递为一个列表,可以多次调用以添加更多数据,例如:

from sqlalchemy import column
from sqlalchemy import values
value_expr = values(
    column('id', Integer),
    column('name', String),
    name="my_values"
).data(
    [(1, 'name1'), (2, 'name2'), (3, 'name3')]
)

参数:

  • *columns – 列表达式,通常使用column()对象组成。
  • name – 此 VALUES 构造的名称。如果省略,VALUES 构造将在 SQL 表达式中无名。不同的后端可能对此有不同的要求。
  • literal_binds – 默认为 False。是否在 SQL 输出中内联呈现数据值,而不是使用绑定参数。## 可选择修饰符构造函数

此处列出的函数通常作为FromClauseSelectable元素的方法更常见,例如,alias()函数通常通过FromClause.alias()方法调用。

对象名称 描述
alias(selectable[, name, flat]) 返回给定FromClause的命名别名。
cte(selectable[, name, recursive]) 返回一个新的 CTE,或者公共表达式实例。
join(left, right[, onclause, isouter, …]) 生成一个给定两个FromClause表达式的Join对象。
lateral(selectable[, name]) 返回一个Lateral对象。
outerjoin(left, right[, onclause, full]) 返回一个 OUTER JOIN 子句元素。
tablesample(selectable, sampling[, name, seed]) 返回一个TableSample对象。
function sqlalchemy.sql.expression.alias(selectable: FromClause, name: str | None = None, flat: bool = False) → NamedFromClause

返回给定FromClause的命名别名。

对于TableJoin对象,返回类型为Alias对象。其他类型的NamedFromClause对象可能会针对其他类型的FromClause对象返回。

命名别名表示任何在 SQL 中分配了替代名称的FromClause,通常在生成时使用 AS 子句,例如 SELECT * FROM table AS aliasname

等效功能可通过FromClause.alias()方法在所有FromClause对象上使用。

参数:

  • selectable – 任何FromClause子类,例如表格,选择语句等。
  • name – 要分配为别名的字符串名称。如果为None,则将在编译时确定性地生成一个名称。确定性意味着该名称保证与同一语句中使用的其他构造唯一,并且对于同一语句对象的每次连续编译也将是相同的名称。
  • flat – 如果给定的可选对象是 Join 的实例,则将传递给 Join.alias() - 有关详细信息,请参阅 Join.alias()
function sqlalchemy.sql.expression.cte(selectable: HasCTE, name: str | None = None, recursive: bool = False) → CTE

返回一个新的 CTE 或公共表达式实例。

请参阅 HasCTE.cte() 了解 CTE 用法的详细信息。

function sqlalchemy.sql.expression.join(left: _FromClauseArgument, right: _FromClauseArgument, onclause: _OnClauseArgument | None = None, isouter: bool = False, full: bool = False) → Join

给定两个 FromClause 表达式,生成一个 Join 对象。

例如:

j = join(user_table, address_table,
         user_table.c.id == address_table.c.user_id)
stmt = select(user_table).select_from(j)

将会生成类似的 SQL:

SELECT user.id, user.name FROM user
JOIN address ON user.id = address.user_id

类似的功能可在任何 FromClause 对象(例如 Table)上使用 FromClause.join() 方法。

参数:

  • left – 连接的左侧。
  • right – 连接的右侧;这是任何 FromClause 对象,例如 Table 对象,也可以是 ORM 映射的类等可选对象。
  • onclause – 表示连接的 ON 子句的 SQL 表达式。如果保留为 NoneFromClause.join() 将尝试根据外键关系连接两个表。
  • isouter – 如果为 True,则渲染一个 LEFT OUTER JOIN,而不是 JOIN。
  • full – 如果为 True,则渲染一个 FULL OUTER JOIN,而不是 JOIN。

另请参见

FromClause.join() - 方法形式,基于给定的左侧。

Join - 生成的对象类型。

function sqlalchemy.sql.expression.lateral(selectable: SelectBase | _FromClauseArgument, name: str | None = None) → LateralFromClause

返回一个 Lateral 对象。

Lateral 是表示具有 LATERAL 关键字的子查询的 Alias 子类。

LATERAL 子查询的特殊行为是,它出现在封闭 SELECT 的 FROM 子句中,但可以与该 SELECT 的其他 FROM 子句相关联。这是一种特殊情况的子查询,仅受一小部分后端支持,目前支持较新版本的 PostgreSQL。

另请参见

LATERAL 关联 - 使用概述。

function sqlalchemy.sql.expression.outerjoin(left: _FromClauseArgument, right: _FromClauseArgument, onclause: _OnClauseArgument | None = None, full: bool = False) → Join

返回一个 OUTER JOIN 子句元素。

返回的对象是 Join 的实例。

类似的功能也可通过任何 FromClause 上的 FromClause.outerjoin() 方法获得。

参数:

  • left – 连接的左侧。
  • right – 连接的右侧。
  • onclause – 可选的 ON 子句条件,否则会从左侧和右侧之间建立的外键关系中派生。

要将连接链在一起,请使用结果 Join 对象上的 FromClause.join()FromClause.outerjoin() 方法。

function sqlalchemy.sql.expression.tablesample(selectable: _FromClauseArgument, sampling: float | Function[Any], name: str | None = None, seed: roles.ExpressionElementRole[Any] | None = None) → TableSample

返回一个 TableSample 对象。

TableSample 是一个 Alias 子类,表示应用了 TABLESAMPLE 子句的表。 tablesample() 也可从 FromClause 类中通过 FromClause.tablesample() 方法获得。

TABLESAMPLE 子句允许从表中随机选择近似百分比的行。它支持多种采样方法,最常见的是 BERNOULLI 和 SYSTEM。

例如:

from sqlalchemy import func
selectable = people.tablesample(
            func.bernoulli(1),
            name='alias',
            seed=func.random())
stmt = select(selectable.c.people_id)

假设 people 有一个列 people_id,上述语句将呈现为:

SELECT alias.people_id FROM
people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
REPEATABLE (random())

参数:

  • sampling – 一个介于 0 和 100 之间的 float 百分比或 Function
  • name – 可选别名名称
  • seed – 任意实值 SQL 表达式。当指定时,还会呈现 REPEATABLE 子句。

可选择的类文档

这里的类是使用 可选择的基础构造函数 和 可选择的修饰符构造函数 列出的构造函数生成的。

对象名称 描述
别名 表示表或可选择的别名(AS)。
AliasedReturnsRows 对表、子查询和其他可选择的别名的基类。
CompoundSelect 形成 UNION, UNION ALL, 和其他基于 SELECT 的集合操作的基础。
CTE 表示公共表达式。
Executable ClauseElement标记为支持执行。
Exists 表示一个EXISTS子句。
FromClause 表示可在SELECT语句的FROM子句中使用的元素。
GenerativeSelect SELECT 语句的基类,可以添加额外的元素。
HasCTE 声明一个类包含 CTE 支持的 Mixin。
HasPrefixes
HasSuffixes
Join 表示两个FromClause元素之间的JOIN构造。
Lateral 表示一个 LATERAL 子查询。
ReturnsRows Core 构造的基类,具有某种可以表示行的列的概念。
ScalarSelect 表示一个标量子查询。
ScalarValues 表示可用作语句中 COLUMN 元素的标量VALUES构造。
Select 表示一个SELECT语句。
Selectable 将类标记为可选择。
SelectBase SELECT 语句的基类。
Subquery 表示一个 SELECT 的子查询。
TableClause 表示最小的“表”构造。
TableSample 表示一个 TABLESAMPLE 子句。
TableValuedAlias 对“表值”SQL 函数的别名。
TextualSelect TextClause构造内部包装一个SelectBase接口。
Values 表示可用作语句中 FROM 元素的VALUES构造。
class sqlalchemy.sql.expression.Alias

表示一个表或可选择的别名(AS)。

表示别名,通常使用AS关键字(或在某些数据库上不使用关键字,如 Oracle)应用于 SQL 语句中的任何表或子选择。

此对象是从alias()模块级函数以及所有FromClause子类上可用的FromClause.alias()方法构造的。

另请参阅

FromClause.alias()

成员

inherit_cache

类签名

sqlalchemy.sql.expression.Aliassqlalchemy.sql.roles.DMLTableRolesqlalchemy.sql.expression.FromClauseAlias

attribute inherit_cache: bool | None = True

指示此HasCacheKey实例是否应使用其直接超类使用的缓存键生成方案。

此属性默认为None,表示构造尚未考虑是否应该参与缓存;这在功能上等同于将值设置为False,除了还会发出警告。

如果与此类本地属性而不是其超类相关的属性不会更改对象对应的 SQL,则可以将此标志设置为True

另请参阅

启用自定义构造的缓存支持 - 设置第三方或用户定义的 SQL 构造的HasCacheKey.inherit_cache属性的通用指南。

class sqlalchemy.sql.expression.AliasedReturnsRows

别名对表、子查询和其他可选择项的基类。

成员

description, is_derived_from(), original

类签名

sqlalchemy.sql.expression.AliasedReturnsRowssqlalchemy.sql.expression.NoInitsqlalchemy.sql.expression.NamedFromClause

attribute description
method is_derived_from(fromclause: FromClause | None) → bool

如果此FromClause是从给定的FromClause“派生”的话,则返回True

一个例子是表的别名是从该表派生的。

attribute original

适用于引用 Alias.original 的方言的遗留。

class sqlalchemy.sql.expression.CompoundSelect

形成UNIONUNION ALL和其他基于 SELECT 的集合操作的基础。

另请参阅

union()

union_all()

intersect()

intersect_all()

except()

except_all()

成员

add_cte(), alias(), as_scalar(), c, corresponding_column(), cte(),  execution_options(), exists(), exported_columns, fetch(),  get_execution_options(), get_label_style(), group_by(),  is_derived_from(), label(), lateral(), limit(), offset(), options(),  order_by(), replace_selectable(), scalar_subquery(), select(),  selected_columns, self_group(), set_label_style(), slice(), subquery(),  with_for_update()

类签名

sqlalchemy.sql.expression.CompoundSelect (sqlalchemy.sql.expression.HasCompileState, sqlalchemy.sql.expression.GenerativeSelect, sqlalchemy.sql.expression.ExecutableReturnsRows)

method add_cte(*ctes: CTE, nest_here: bool = False) → Self

继承自 HasCTE.add_cte() 方法的 HasCTE

向此语句添加一个或多个CTE构造。

此方法将给定的CTE构造与父语句关联,以便它们将无条件地在最终语句的 WITH 子句中呈现,即使在语句或任何子选择中没有其他地方引用它们。

当设置为 True 时,可选的HasCTE.add_cte.nest_here参数将使每个给定的CTE在与此语句直接一起呈现的 WITH 子句中呈现,而不是将其移动到最终呈现语句的顶部,即使此语句作为较大语句中的子查询呈现。

此方法有两个一般用途。一个是嵌入一些用途的 CTE 语句,而不被明确引用,例如将 DML 语句(如 INSERT 或 UPDATE)作为  CTE 内联到可能间接从其结果中获取的主语句中的用例。另一个是提供对应该保持直接呈现的特定一系列 CTE  构造的放置的控制,这些构造可能嵌套在较大语句中。

例如:

from sqlalchemy import table, column, select
t = table('t', column('c1'), column('c2'))
ins = t.insert().values({"c1": "x", "c2": "y"}).cte()
stmt = select(t).add_cte(ins)

将呈现为:

WITH anon_1 AS
(INSERT INTO t (c1, c2) VALUES (:param_1, :param_2))
SELECT t.c1, t.c2
FROM t

在上面的示例中,“anon_1” CTE 在 SELECT 语句中未被引用,但仍完成运行 INSERT 语句的任务。

类似地,在与 DML 相关的上下文中,使用 PostgreSQL Insert构造生成“upsert”:

from sqlalchemy import table, column
from sqlalchemy.dialects.postgresql import insert
t = table("t", column("c1"), column("c2"))
delete_statement_cte = (
    t.delete().where(t.c.c1 < 1).cte("deletions")
)
insert_stmt = insert(t).values({"c1": 1, "c2": 2})
update_statement = insert_stmt.on_conflict_do_update(
    index_elements=[t.c.c1],
    set_={
        "c1": insert_stmt.excluded.c1,
        "c2": insert_stmt.excluded.c2,
    },
).add_cte(delete_statement_cte)
print(update_statement)

上述语句呈现为:

WITH deletions AS
(DELETE FROM t WHERE t.c1 < %(c1_1)s)
INSERT INTO t (c1, c2) VALUES (%(c1)s, %(c2)s)
ON CONFLICT (c1) DO UPDATE SET c1 = excluded.c1, c2 = excluded.c2

从版本 1.4.21 开始新增。

参数:

  • *ctes
    零个或多个CTE构造。
    从版本 2.0 开始更改:接受多个 CTE 实例
  • nest_here
    如果为 True,则给定的 CTE 或 CTEs 将被呈现为当它们被添加到此HasCTE时指定HasCTE.cte.nesting标志为True。假设给定的 CTEs 在外部封闭语句中也没有被引用,当给出此标志时,给定的 CTEs 应在此语句级别呈现。
    从版本 2.0 开始新增。
    另请参阅
    HasCTE.cte.nesting
method alias(name: str | None = None, flat: bool = False) → Subquery

继承自 SelectBase.alias() 方法的 SelectBase

返回针对此 SelectBase 的命名子查询。

对于 SelectBase(而不是 FromClause),这将返回一个行为大部分与用于 FromClauseAlias 对象相同的 Subquery 对象。

自版本 1.4 起更改:SelectBase.alias() 方法现在是 SelectBase.subquery() 方法的同义词。

method as_scalar() → ScalarSelect[Any]

继承自 SelectBase.as_scalar() 方法的 SelectBase

自版本 1.4 起弃用:SelectBase.as_scalar() 方法已被弃用,并将在将来的版本中移除。请参考 SelectBase.scalar_subquery()

attribute c

继承自 SelectBase.c 属性的 SelectBase

自版本 1.4 起弃用:SelectBase.cSelectBase.columns 属性已被弃用,并将在将来的版本中移除;这些属性隐式创建一个子查询,应该明确指定。请先调用 SelectBase.subquery() 来创建一个子查询,然后再包含此属性。要访问此 SELECT 对象所选择的列,请使用 SelectBase.selected_columns 属性。

method corresponding_column(column: KeyedColumnElement[Any], require_embedded: bool = False) → KeyedColumnElement[Any] | None

继承自 Selectable.corresponding_column() 方法的 Selectable

给定一个ColumnElement,从这个SelectableSelectable.exported_columns集合中返回对应于原始ColumnElement的导出ColumnElement对象,通过一个共同的祖先列。

参数:

  • column – 要匹配的目标ColumnElement
  • require_embedded – 只返回给定ColumnElement的相应列,如果给定的ColumnElement实际上存在于此Selectable的子元素之内。通常,如果列仅与此Selectable的导出列之一共享一个共同的祖先,则列将匹配。

另请参阅

Selectable.exported_columns - 用于操作的ColumnCollection

ColumnCollection.corresponding_column() - 实现方法。

method cte(name: str | None = None, recursive: bool = False, nesting: bool = False) → CTE

继承自 HasCTE HasCTE.cte() *方法。

返回一个新的CTE或通用表达式实例。

公共表达式是 SQL 标准,其中 SELECT 语句可以利用与主要语句一起指定的辅助语句,使用一个称为“WITH”的子句。还可以采用有关 UNION 的特殊语义,以允许“递归”查询,其中 SELECT 语句可以利用先前已选择的行集。

CTEs 也可以应用于某些数据库上的 DML 构造 UPDATE、INSERT 和 DELETE,既作为与 RETURNING 结合使用时 CTE 行的源,也作为 CTE 行的使用者。

SQLAlchemy 检测到 CTE 对象,这些对象与 Alias 对象类似,被视为要传递到语句的 FROM 子句以及语句顶部的 WITH 子句的特殊元素。

对于特殊前缀,如 PostgreSQL 的 “MATERIALIZED” 和 “NOT MATERIALIZED”,可以使用 CTE.prefix_with() 方法来建立这些。

1.3.13 版本更改:增加了对前缀的支持。特别是 - MATERIALIZED 和 NOT MATERIALIZED。

参数:

  • name – 给公共表达式的名称。类似于 FromClause.alias(),名称可以保留为 None,在这种情况下,将在查询编译时使用匿名符号。
  • recursive – 如果为 True,将呈现 WITH RECURSIVE。递归公共表达式旨在与 UNION ALL 结合使用,以从已选择的行中派生行。
  • nesting
    如果为 True,将在引用它的语句中本地呈现 CTE。对于更复杂的情况,还可以使用 HasCTE.add_cte() 方法,使用 HasCTE.add_cte.nest_here 参数更精确地控制特定 CTE 的精确放置。
    1.4.24 版本新增。
    另请参阅
    HasCTE.add_cte()

以下示例包括两个来自 PostgreSQL 文档的示例 www.postgresql.org/docs/current/static/queries-with.html,以及其他示例。

示例 1,非递归:

from sqlalchemy import (Table, Column, String, Integer,
                        MetaData, select, func)
metadata = MetaData()
orders = Table('orders', metadata,
    Column('region', String),
    Column('amount', Integer),
    Column('product', String),
    Column('quantity', Integer)
)
regional_sales = select(
                    orders.c.region,
                    func.sum(orders.c.amount).label('total_sales')
                ).group_by(orders.c.region).cte("regional_sales")
top_regions = select(regional_sales.c.region).\
        where(
            regional_sales.c.total_sales >
            select(
                func.sum(regional_sales.c.total_sales) / 10
            )
        ).cte("top_regions")
statement = select(
            orders.c.region,
            orders.c.product,
            func.sum(orders.c.quantity).label("product_units"),
            func.sum(orders.c.amount).label("product_sales")
    ).where(orders.c.region.in_(
        select(top_regions.c.region)
    )).group_by(orders.c.region, orders.c.product)
result = conn.execute(statement).fetchall()

示例 2,WITH RECURSIVE:

from sqlalchemy import (Table, Column, String, Integer,
                        MetaData, select, func)
metadata = MetaData()
parts = Table('parts', metadata,
    Column('part', String),
    Column('sub_part', String),
    Column('quantity', Integer),
)
included_parts = select(\
    parts.c.sub_part, parts.c.part, parts.c.quantity\
    ).\
    where(parts.c.part=='our part').\
    cte(recursive=True)
incl_alias = included_parts.alias()
parts_alias = parts.alias()
included_parts = included_parts.union_all(
    select(
        parts_alias.c.sub_part,
        parts_alias.c.part,
        parts_alias.c.quantity
    ).\
    where(parts_alias.c.part==incl_alias.c.sub_part)
)
statement = select(
            included_parts.c.sub_part,
            func.sum(included_parts.c.quantity).
              label('total_quantity')
        ).\
        group_by(included_parts.c.sub_part)
result = conn.execute(statement).fetchall()

示例 3,使用 UPDATE 和 INSERT 进行 upsert 的 CTE:

from datetime import date
from sqlalchemy import (MetaData, Table, Column, Integer,
                        Date, select, literal, and_, exists)
metadata = MetaData()
visitors = Table('visitors', metadata,
    Column('product_id', Integer, primary_key=True),
    Column('date', Date, primary_key=True),
    Column('count', Integer),
)
# add 5 visitors for the product_id == 1
product_id = 1
day = date.today()
count = 5
update_cte = (
    visitors.update()
    .where(and_(visitors.c.product_id == product_id,
                visitors.c.date == day))
    .values(count=visitors.c.count + count)
    .returning(literal(1))
    .cte('update_cte')
)
upsert = visitors.insert().from_select(
    [visitors.c.product_id, visitors.c.date, visitors.c.count],
    select(literal(product_id), literal(day), literal(count))
        .where(~exists(update_cte.select()))
)
connection.execute(upsert)

示例 4,嵌套 CTE(SQLAlchemy 1.4.24 及以上版本):

value_a = select(
    literal("root").label("n")
).cte("value_a")
# A nested CTE with the same name as the root one
value_a_nested = select(
    literal("nesting").label("n")
).cte("value_a", nesting=True)
# Nesting CTEs takes ascendency locally
# over the CTEs at a higher level
value_b = select(value_a_nested.c.n).cte("value_b")
value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b"))

上述查询将第二个 CTE 嵌套在第一个内部,如下所示带有内联参数:

WITH
    value_a AS
        (SELECT 'root' AS n),
    value_b AS
        (WITH value_a AS
            (SELECT 'nesting' AS n)
        SELECT value_a.n AS n FROM value_a)
SELECT value_a.n AS a, value_b.n AS b
FROM value_a, value_b

可以使用 HasCTE.add_cte() 方法来设置相同的 CTE(SQLAlchemy 2.0 及以上版本):

value_a = select(
    literal("root").label("n")
).cte("value_a")
# A nested CTE with the same name as the root one
value_a_nested = select(
    literal("nesting").label("n")
).cte("value_a")
# Nesting CTEs takes ascendency locally
# over the CTEs at a higher level
value_b = (
    select(value_a_nested.c.n).
    add_cte(value_a_nested, nest_here=True).
    cte("value_b")
)
value_ab = select(value_a.c.n.label("a"), value_b.c.n.label("b"))

示例 5,非线性 CTE(SQLAlchemy 1.4.28 及以上版本):

edge = Table(
    "edge",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("left", Integer),
    Column("right", Integer),
)
root_node = select(literal(1).label("node")).cte(
    "nodes", recursive=True
)
left_edge = select(edge.c.left).join(
    root_node, edge.c.right == root_node.c.node
)
right_edge = select(edge.c.right).join(
    root_node, edge.c.left == root_node.c.node
)
subgraph_cte = root_node.union(left_edge, right_edge)
subgraph = select(subgraph_cte)

上述查询将在递归 CTE 中呈现 2 个 UNION:

WITH RECURSIVE nodes(node) AS (
        SELECT 1 AS node
    UNION
        SELECT edge."left" AS "left"
        FROM edge JOIN nodes ON edge."right" = nodes.node
    UNION
        SELECT edge."right" AS "right"
        FROM edge JOIN nodes ON edge."left" = nodes.node
)
SELECT nodes.node FROM nodes

另请参阅

Query.cte() - HasCTE.cte() 的 ORM 版本。

method execution_options(**kw: Any) → Self

继承自 Executable.execution_options() 方法的 Executable

为语句设置在执行期间生效的非 SQL 选项。

可以在许多范围内设置执行选项,包括每个语句、每个连接或每次执行,使用诸如Connection.execution_options()之类的方法和接受选项字典的参数,如Connection.execute.execution_optionsSession.execute.execution_options

执行选项的主要特征,与其他类型的选项(如 ORM 加载器选项)相反,是执行选项永远不会影响查询的编译 SQL,只会影响 SQL 语句本身的调用方式或结果的获取方式。也就是说,执行选项不是 SQL 编译所考虑的内容,也不被视为语句的缓存状态的一部分。

Executable.execution_options() 方法是生成的,就像应用于EngineQuery对象的方法一样,这意味着当调用该方法时,会返回对象的副本,将给定的参数应用于该新副本,但原始对象保持不变:

statement = select(table.c.x, table.c.y)
new_statement = statement.execution_options(my_option=True)

这种行为的一个例外是Connection对象,其中Connection.execution_options()方法明确地不是生成的。

可传递给 Executable.execution_options() 和其他相关方法和参数字典的选项类型包括由  SQLAlchemy Core 或 ORM 明确消耗的参数,以及未由 SQLAlchemy  定义的任意关键字参数,这意味着可以使用这些方法和/或参数字典来处理与自定义代码交互的用户定义参数,该自定义代码可以使用诸如 Executable.get_execution_options()Connection.get_execution_options() 的方法访问这些参数,或者在选择的事件钩子中使用专用的 execution_options 事件参数,如 ConnectionEvents.before_execute.execution_optionsORMExecuteState.execution_options。例如:

from sqlalchemy import event
@event.listens_for(some_engine, "before_execute")
def _process_opt(conn, statement, multiparams, params, execution_options):
    "run a SQL function before invoking a statement"
    if execution_options.get("do_special_thing", False):
        conn.exec_driver_sql("run_special_function()")

在 SQLAlchemy 明确识别的选项范围内,大多数适用于特定类对象而不适用于其他类对象。最常见的执行选项包括:

  • Connection.execution_options.isolation_level - 通过 Engine 为连接或一类连接设置隔离级别。此选项仅由 ConnectionEngine 接受。
  • Connection.execution_options.stream_results - 指示应使用服务器端游标获取结果;此选项由 Connection 接受,在 Connection.execute()execution_options 参数上,以及在 SQL 语句对象上的 Executable.execution_options() 上,以及像 Session.execute() 这样的 ORM 构造函数。
  • Connection.execution_options.compiled_cache - 指示一个将用作 ConnectionEngine 的 SQL 编译缓存 的字典,以及像 Session.execute() 这样的 ORM 方法。可以传递 None 来禁用语句的缓存。此选项不被 Executable.execution_options() 接受,因为在语句对象中携带编译缓存是不可取的。
  • Connection.execution_options.schema_translate_map - 模式翻译映射 功能使用的模式名称的映射,由 ConnectionEngineExecutable 接受,以及像 Session.execute() 这样的 ORM 构造函数。

另请参阅

Connection.execution_options()

Connection.execute.execution_options

Session.execute.execution_options

ORM 执行选项 - 所有 ORM 特定执行选项的文档

method exists() → Exists

继承自 SelectBase.exists() 方法的 SelectBase

返回此可选择性的 Exists 表示,可用作列表达式。

返回的对象是 Exists 的一个实例。

另请参阅

exists()

EXISTS 子查询 - 在 2.0 风格 教程中。

版本 1.4 中的新功能。

attribute exported_columns

继承自 SelectBase.exported_columns 属性的 SelectBase

一个 ColumnCollection 代表此 Selectable 的“导出”列,不包括 TextClause 结构。

一个 SelectBase 对象的“导出”列与 SelectBase.selected_columns 集合是同义词。

版本 1.4 中的新功能。

另请参阅

Select.exported_columns

Selectable.exported_columns

FromClause.exported_columns

method fetch(count: _LimitOffsetType, with_ties: bool = False, percent: bool = False) → Self

继承自 GenerativeSelect.fetch() 方法的 GenerativeSelect

返回一个应用了给定 FETCH FIRST 标准的新可选择性。

这是一个数字值,通常在结果选择中呈现为FETCH {FIRST | NEXT} [ count ] {ROW | ROWS} {ONLY | WITH TIES}表达式。此功能目前已在 Oracle、PostgreSQL、MSSQL 上实现。

使用 GenerativeSelect.offset() 来指定偏移量。

注意

GenerativeSelect.fetch() 方法将替换应用了 GenerativeSelect.limit() 的任何子句。

自版本 1.4 起新增。


SqlAlchemy 2.0 中文文档(三十五)(2)https://developer.aliyun.com/article/1562892

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(二十九)(3)
SqlAlchemy 2.0 中文文档(二十九)
36 4
|
3月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(二十九)(2)
SqlAlchemy 2.0 中文文档(二十九)
34 7
|
3月前
|
SQL 缓存 关系型数据库
SqlAlchemy 2.0 中文文档(三十五)(2)
SqlAlchemy 2.0 中文文档(三十五)
35 2
|
3月前
|
SQL 缓存 关系型数据库
SqlAlchemy 2.0 中文文档(三十五)(4)
SqlAlchemy 2.0 中文文档(三十五)
25 1
|
3月前
|
SQL 存储 关系型数据库
SqlAlchemy 2.0 中文文档(二十九)(1)
SqlAlchemy 2.0 中文文档(二十九)
41 4
|
3月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(三十四)(5)
SqlAlchemy 2.0 中文文档(三十四)
35 0
|
3月前
|
SQL 存储 关系型数据库
SqlAlchemy 2.0 中文文档(三十四)(4)
SqlAlchemy 2.0 中文文档(三十四)
37 1
|
3月前
|
JSON 测试技术 数据格式
SqlAlchemy 2.0 中文文档(三十一)(4)
SqlAlchemy 2.0 中文文档(三十一)
31 1
|
3月前
|
SQL 数据库 Python
SqlAlchemy 2.0 中文文档(三十一)(3)
SqlAlchemy 2.0 中文文档(三十一)
23 1
|
3月前
|
SQL 测试技术 数据库
SqlAlchemy 2.0 中文文档(三十一)(2)
SqlAlchemy 2.0 中文文档(三十一)
24 1