SQLALchemy Core 中是否有类似 func.group_concat() 的东西会返回对象列表,而不是字符串?

问题描述 投票:0回答:1

是否有约定/是否可以返回列中嵌套对象的数组/列表,例如来自连接的多对多表?

例如,假设我有三个标准化表:“movies”、“actors”和一个联结表“actors_in_movies”。我想检索多部电影,每行一部电影,并在其行中包含该电影的演员列表。

连接表上的基本 SELECT 语句将检索:

《比尔和泰德的奇妙冒险》、《基努·里维斯》
《比尔和泰德的奇妙冒险》、《亚历克斯·温特》
《比尔和泰德的奇妙冒险》、《乔治·卡林》
《黑客帝国》、《基努·里维斯》
《黑客帝国》、《凯莉-安·莫斯》
《黑客帝国》、《劳伦斯·菲什伯恩》

使用 func.group_concat() 我可以检索:
“比尔和泰德的奇妙冒险”、“基努·里维斯、亚历克斯·温特、乔治·卡林”
《黑客帝国》、《基努·里维斯、凯莉-安·莫斯、劳伦斯·菲什伯恩》

使用 GROUP_BY 和像 COUNT 这样的聚合函数我可以检索:
“比尔和泰德的奇妙冒险”,3
《黑客帝国》,3

但是 SQL(以及扩展的 SQL Alchemy Core)是否支持返回一些我可以访问嵌套聚合结果的内容,例如:
“比尔和泰德的奇妙冒险”、[“基努·里维斯”、“亚历克斯·温特”、“乔治·卡林”]
《黑客帝国》、[《基努·里维斯》、《凯莉·安·莫斯》、《劳伦斯·菲什伯恩》]

我知道这是 SQLAlchemy ORM 的主要用例 - 是否有一种传统方法可以使用纯 SQL/SQL Alchemy Core 来管理它?是否需要多次查询?还是通常留给应用层来管理?

select database-design sqlalchemy aggregate-functions
1个回答
0
投票

有没有一种传统的方法来使用纯 SQL/SQL Alchemy Core 来管理这个问题?

简而言之:不,Core 中没有这种独立于数据库的机制。这就是 ORM 的用途。

但是,Core 可以在特定数据库中利用这样的功能。例如,PostgreSQL 有

array_agg()
:

from sqlalchemy import Column, ForeignKey, Integer, MetaData, String, Table, create_engine, func, insert, select

engine = create_engine("postgresql://scott:[email protected]/test")

meta = MetaData()

movie = Table(
    "movie",
    meta,
    Column("id", Integer, primary_key=True, autoincrement=False),
    Column("title", String, nullable=False),
)

actor = Table(
    "actor",
    meta,
    Column("id", Integer, primary_key=True, autoincrement=False),
    Column("name", String, nullable=False),
)

actor_in_movie = Table(
    "actor_in_movie",
    meta,
    Column("actor_id", Integer, ForeignKey("actor.id"), primary_key=True),
    Column("movie_id", Integer, ForeignKey("movie.id"), primary_key=True),
)

meta.drop_all(engine)
meta.create_all(engine)

# populate example data
with engine.begin() as conn:
    conn.execute(
        insert(movie),
        [
            dict(id=1, title="Bill & Ted's Excellent Adventure"),
        ],
    )
    conn.execute(
        insert(actor),
        [
            dict(id=1, name="Reeves, Keanu"),
            dict(id=2, name="Carlin, George"),
        ],
    )
    conn.execute(
        insert(actor_in_movie),
        [
            dict(actor_id=1, movie_id=1),
            dict(actor_id=2, movie_id=1),
        ],
    )

with engine.begin() as conn:
    qry = (
        select(movie.c.title, func.array_agg(actor.c.name).label("actors"))
        .select_from(actor)
        .join(actor_in_movie)
        .join(movie)
        .group_by(movie.c.title)
    )
    result = conn.execute(qry)
    for row in result:
        print(row)
        # ("Bill & Ted's Excellent Adventure", ['Reeves, Keanu', 'Carlin, George'])
        print(type(row.actors))  # <class 'list'>
        print(type(row.actors[0]))  # <class 'str'>
© www.soinside.com 2019 - 2024. All rights reserved.