python - SQLAlchemy 嵌套 CTE 查询

标签 python sql postgresql sqlalchemy

sqlalchemy 核心查询构建器似乎取消嵌套并将 CTE 查询重新定位到已编译 sql 的“顶部”。

我正在转换现有的 Postgres 查询,该查询选择深度连接的数据作为单个 JSON 对象。语法非常人为,但它显着减少了大型查询的网络开销。目标是使用 sqlalchemy 核心查询构建器动态构建查询。

这是嵌套 CTE 的最小工作示例

with res_cte as (
    select
        account_0.name acct_name,
        (
            with offer_cte as (
                select
                    offer_0.id
                from
                    offer offer_0
                where
                    offer_0.account_id = account_0.id
            )
            select
                array_agg(offer_cte.id)
            from
                offer_cte
        ) as offer_arr
    from
        account account_0
)
select 
    acct_name::text, offer_arr::text
from res_cte

结果
acct_name,  offer_arr
---------------------
oliver,     null
rachel,     {3}
buddy,      {4,5}

(我的错误使用)核心查询构建器试图取消嵌套 offer_cte并导致每个 offer.id与每个 account_name 相关联结果中。

无需在答案中重新实现这个确切的查询,任何导致类似嵌套 CTE 的示例都是完美的。

最佳答案

我刚刚实现了嵌套 cte 功能。它应该以 1.4.24 版本发布。
拉取请求:https://github.com/sqlalchemy/sqlalchemy/pull/6709

import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base

# Model declaration
Base = declarative_base()

class Offer(Base):
    __tablename__ = "offer"
    
    id = sa.Column(sa.Integer, primary_key=True)
    account_id = sa.Column(sa.Integer, nullable=False)
    
class Account(Base):
    __tablename__ = "account"

    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.TEXT, nullable=False)

# Query construction
account_0 = sa.orm.aliased(Account)

# Watch the nesting keyword set to True
offer_cte = (
    sa.select(Offer.id)
    .where(Offer.account_id == account_0.id)
    .select_from(Offer)
    .correlate(account_0).cte("offer_cte", nesting=True)
)
offer_arr = sa.select(sa.func.array_agg(offer_cte.c.id).label("offer_arr"))

res_cte = sa.select(
    account_0.name.label("acct_name"),
    offer_arr.scalar_subquery().label("offer_arr"),
).cte("res_cte")

final_query = sa.select(
    sa.cast(res_cte.c.acct_name, sa.TEXT),
    sa.cast(res_cte.c.offer_arr, sa.TEXT),
)
它构造此查询,返回您期望的结果:
WITH res_cte AS 
(
    SELECT
        account_1.name AS acct_name
        , (
            WITH offer_cte AS 
(
                SELECT
                    offer.id AS id
                FROM
                    offer
                WHERE
                    offer.account_id = account_1.id
            )
            SELECT
                array_agg(offer_cte.id) AS offer_arr
            FROM
                offer_cte
        ) AS offer_arr
    FROM
        account AS account_1
)
 SELECT
    CAST(res_cte.acct_name AS TEXT) AS acct_name
    , CAST(res_cte.offer_arr AS TEXT) AS offer_arr
FROM
    res_cte

关于python - SQLAlchemy 嵌套 CTE 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58513337/

相关文章:

Python Pandas : Convert Rows as Column headers

python - (Python 3) 输出问题

sql - SQLite3条件插入?

php - PDO 查询中的 SQL 语法错误

java - Hibernate:如何使用 HQL 选择空对象?

postgresql - 有没有办法在没有 CASE 表达式的情况下做到这一点?

python - 在每个 View 中渲染动态菜单

Python,BeautifulSoup,重新: How to convert extracted texts to dictionary from web?

database - 将 postgres 服务器扩展到多个服务器

PostgreSQL 查询使用索引扫描运行得更快,但引擎选择散列连接