【问题标题】:SQLAlchemy group_by SQLite vs PostgreSQLSQLAlchemy group_by SQLite vs PostgreSQL
【发布时间】:2016-04-23 09:54:18
【问题描述】:

对于我们正在构建的 Web 应用程序,我们使用 SQLite 进行测试。最近我们想迁移到 PostgreSQL。这就是问题开始的地方:

我们有这个 SQLAlchemy 模型(简化)

class Entity(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    i_want_this = db.Column(db.String)
    some_value = db.Column(db.Integer)

我想将所有Entitys 按some_value 分组,我这样做了(简化):

db.session.query(Entity, db.func.count()).group_by(Entity.some_value)

在 SQLite 中这行得通。回想起来,我发现它没有意义,但 SQLite 确实有意义。我无法确定返回了哪些实体。

现在在 PostgrSQL 中我们得到这个错误:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) column "entity.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT entity.id AS entity_id, entity.i_want_this AS entity_not...
^
[SQL: 'SELECT entity.id AS entity_id, entity.i_want_this AS entity_i_want_this, count(*) AS count_1 \nFROM entity GROUP BY entity.some_value']

这个错误完全有道理。

所以我的第一个问题是:为什么 SQLite 允许这样做以及它是如何做到的(使用什么隐藏聚合)?

我的第二个问题很明显:我将如何使用 PostgreSQL?

我实际上只对计数和第一个 i_want_this 值感兴趣。所以我可以这样做:

groups = db.session.query(db.func.min(Entity.id), db.func.count()).group_by(Entity.some_value)

[(Entity.query.get(id_), count) for id_, count in groups]

但我不想要这些额外的get 查询。

所以我想选择第一个实体(具有最小 id 的实体)和由some_value 或第一个i_want_this 分组的实体数和由some_value 分组的计数

编辑以明确:

  • 我想按some_value 分组(完成
  • 我想获取每个组中的实体数量(完成
  • 我想获得每个组中id 最低的实体(需要帮助
  • 或者我想获取每个组中id 最低的实体的i_want_this 值(需要帮助

【问题讨论】:

  • SQLite 从组中的随机行返回一个值。但是“第一”是什么意思? SQL 表未排序。
  • 我的意思是在我上一个代码 sn-p 中看到的具有最低 id 的实体。

标签: python postgresql sqlite group-by sqlalchemy


【解决方案1】:

关于您的第一个问题,请查看documentation

然后对结果集中的每个表达式进行一次评估 行组。如果表达式是一个聚合表达式,它是 对组中的所有行进行评估。否则,它被评估 针对从组内任意选择的单个行。如果 结果集中有多个非聚合表达式, 那么所有这样的表达式都会针对同一行进行评估。

关于第二个问题,考虑到您当前在 SQLite 中的查询也或多或少地返回随机结果,您可能需要解释您实际想要实现的目标。

编辑: 要获取每个组具有最小 id 的实体,可以使用 Query.select_from 构造:

import sqlalchemy.sql as sa_sql

# create the aggregate/grouped query
grouped = sa_sql.select([sa_sql.func.min(Entity.id).label('min_id')])\
                .group_by(Entity.some_value)\
                .alias('grouped')

# join it with the full entities table
joined = sa_sql.join(Entity, grouped, grouped.c.min_id == Entity.id)
# and let sqlalchemy pull the entities from this statement:
session.query(Entity).select_from(joined)

这将产生以下 SQL:

SELECT entities.id AS entities_id,
       entities.i_want_this AS entities_i_want_this,
       entities.some_value AS entities_some_value 
FROM entities JOIN (SELECT min(entities.id) AS min_id
                    FROM entities GROUP BY entities.some_value) AS grouped
ON grouped.min_id = entities.id

【讨论】:

    猜你喜欢
    • 2012-01-06
    • 1970-01-01
    • 2012-11-24
    • 2011-02-10
    • 2014-05-24
    • 2020-07-24
    • 2021-02-26
    • 1970-01-01
    • 2018-01-28
    相关资源
    最近更新 更多