在 SQLAlchemy 中编写查询以计算出现次数和存储 ID

Writing a query in SQLAlchemy to count occurrences and store IDs

我正在使用 SQLAlchemy 处理 postgres 数据库。

我有一个table这样的

class Author(Base):
    __tablename__ = "Author"
    ID = Column(BIGINT, primary_key=True)
    name = Column(Unicode)

我想识别所有同名作者并将他们的 ID 保存在列表中。

例如,如果在数据库中有 2 位作者名为“John”,3 位作者名为“Jack”,ID 分别为 11、22、33、44 和 55,我希望查询 return

[("John", [11,22]), ("Jack", [33,44,55])]

目前我已经能够写作

[x for x in db_session.query(
          func.count(Author.name),
          Author.name
          ).group_by(Author.name) if x[0]>1]

但这只是让我回想起事件

[(2,"John"),(3,"Jack")]

非常感谢您的帮助!

在 SQL 中执行此操作的方法是使用 PostgreSQL 的 array_agg 函数将 id 分组到一个数组中:

SELECT
    name,
    array_agg(id) AS ids
FROM
    my_table
GROUP BY
    name
HAVING
    count(name) > 1;

array_agg函数收集每个名称的id,HAVING子句排除那些只有一行的。查询的输出如下所示:

 name  │        ids         
═══════╪════════════════════
 Alice │ {2,4,9,10,16}
 Bob   │ {1,6,11,12,13}
 Carol │ {3,5,7,8,14,15,17}

翻译成 SQLAlchemy,查询将如下所示:

import sqlalchemy as sa
...
q = (
    db_session.query(Author.name, sa.func.array_agg(Author.id).label('ids'))
    .group_by(Author.name)
    .having(sa.func.count(Author.name) > 1)
)

调用 q.all() 将 return 一个包含 (name, [ids]) 个元组的列表,如下所示:

[
    ('Alice', [2, 4, 9, 10, 16]),
    ('Bob', [1, 6, 11, 12, 13]),
    ('Carol', [3, 5, 7, 8, 14, 15, 17]),
]

在 SQLAlchemy 1.4/2.0 风格的等效语法中是:

with Session() as s:
    q = (
        sa.select(Author.name, sa.func.array_agg(Author.id).label('ids'))
        .group_by(Author.name)
        .having(sa.func.count(Author.name) > 1)
    )
    res = s.execute(q)