>>> stmt = select(
... func.row_number().over(partition_by=user_table.c.name),
... user_table.c.name,
... address_table.c.email_address
... ).select_from(user_table).join(address_table)
>>> with engine.connect() as conn:
... result = conn.execute(stmt)
... print(result.all())
BEGIN (implicit)
SELECT row_number() OVER (PARTITION BY user_account.name) AS anon_1,
user_account.name, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
[...] ()
[(1, 'sandy', 'sandy@sqlalchemy.org'), (2, 'sandy', 'sandy@squirrelpower.org'), (1, 'spongebob', 'spongebob@sqlalchemy.org')]
ROLLBACK
上图是 FunctionElement.over.partition_by 参数,以便 PARTITION BY 该条款在OVER条款内呈现。我们也可以利用 ORDER BY 子句使用 FunctionElement.over.order_by :
>>> stmt = select(
... func.count().over(order_by=user_table.c.name),
... user_table.c.name,
... address_table.c.email_address).select_from(user_table).join(address_table)
>>> with engine.connect() as conn:
... result = conn.execute(stmt)
... print(result.all())
BEGIN (implicit)
SELECT count(*) OVER (ORDER BY user_account.name) AS anon_1,
user_account.name, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
[...] ()
[(2, 'sandy', 'sandy@sqlalchemy.org'), (2, 'sandy', 'sandy@squirrelpower.org'), (3, 'spongebob', 'spongebob@sqlalchemy.org')]
ROLLBACK
窗口函数的其他选项包括范围的使用;请参见 over() 查看更多示例。
小技巧
需要注意的是, FunctionElement.over() 方法仅应用于那些实际上是聚合函数的SQL函数;而 Over 构造将很高兴地为任何给定的SQL函数呈现自身,如果该函数本身不是SQL聚合函数,则数据库将拒绝该表达式。
集团内特殊修改器,过滤
“组内”SQL语法与“有序集”或“假设集”聚合函数一起使用。常见的“有序集”函数包括 percentile_cont() 和 rank() 。SQLAlChemy包括内置实现 rank , dense_rank , mode , percentile_cont 和 percentile_disc 其中包括一
个 FunctionElement.within_group() 方法:
>>> print(
... func.unnest(
... func.percentile_disc([0.25,0.5,0.75,1]).within_group(user_table.c.name)
... )
... )
unnest(percentile_disc(:percentile_disc_1) WITHIN GROUP (ORDER BY user_account.name))
某些后端支持“过滤”,以将聚合函数的范围限制为与返回的总行范围相比的特定行子集,可使用 FunctionElement.filter() 方法:
>>> stmt = select(
... func.count(address_table.c.email_address).filter(user_table.c.name == 'sandy'),
... func.count(address_table.c.email_address).filter(user_table.c.name == 'spongebob')
... ).select_from(user_table).join(address_table)
>>> with engine.connect() as conn:
... result = conn.execute(stmt)
... print(result.all())
BEGIN (implicit)
SELECT count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_1,
count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_2
FROM user_account JOIN address ON user_account.id = address.user_id
[...] ('sandy', 'spongebob')
[(2, 1)]
ROLLBACK
表值函数
表值SQL函数支持包含命名子元素的标量表示。通常用于JSON和面向数组的函数,以及 generate_series() ,表值函数在FROM子句中指定,然后作为表引用,有时甚至作为列引用。这种形式的函数在PostgreSQL数据库中非常突
出,但是SQLite、Oracle和SQL Server也支持某些形式的表值函数。
参见
表值、表值函数和列值函数、行和元组对象 -在 《PostgreSQL》 文档。
虽然许多数据库支持表值和其他特殊形式,但PostgreSQL往往是对这些功能需求最大的地方。有关PostgreSQL语法的其他示例以及其他功能,请参阅本节。
SQLAlChemy提供了 FunctionElement.table_valued() 方法作为基本的“表值函数”构造,它将把一个 func 对象添加到包含一系列命名列的FROM子句中,该方法基于按位置传递的字符串名称。这将返回一个 TableValuedAlias 对
象,该对象是启用功能的 Alias 可以用作任何其他FROM子句的构造,如 使用别名 。下面我们将说明 json_each() 函数,虽然该函数在PostgreSQL上很常见,但SQLite的现代版本也支持该函数:
>>> onetwothree = func.json_each('["one", "two", "three"]').table_valued("value")
>>> stmt = select(onetwothree).where(onetwothree.c.value.in_(["two", "three"]))
>>> with engine.connect() as conn:
... result = conn.execute(stmt)
... print(result.all())
BEGIN (implicit)
SELECT anon_1.value
FROM json_each(?) AS anon_1
WHERE anon_1.value IN (?, ?)
[...] ('["one", "two", "three"]', 'two', 'three')
[('two',), ('three',)]
ROLLBACK
在上面,我们使用了 json_each() SQLite和PostgreSQL支持的JSON函数,用于生成表值表达式,其中单个列引用为 value ,然后选择其三行中的两行。
参见
表值函数 -在 《PostgreSQL》 文档-本节将详细介绍其他语法,如已知可与PostgreSQL一起使用的特殊列派生和“具有序号”。
列值函数-作为标量列的表值函数
PostgreSQL和Oracle支持的一种特殊语法是引用FROM子句中的函数,然后该函数作为SELECT语句或其他列表达式上下文的COLUMNS子句中的单个列交付。PostgreSQL在以下函数中大量使用此语法 json_array_elements() ,
json_object_keys() , json_each_text() , json_each() 等。
SQLAlChemy将其称为“列值”函数,可通过应用 FunctionElement.column_valued() 修饰符设置为 Function 构造::
>>> from sqlalchemy import select, func
>>> stmt = select(func.json_array_elements('["one", "two"]').column_valued("x"))
>>> print(stmt)
SELECT x
FROM json_array_elements(:json_array_elements_1) AS x
Oracle方言也支持“Column Valued”表单,它可用于自定义SQL函数: