在SQLAlchemy中对多个列求和

时间:2018-02-10 20:21:40

标签: python sql postgresql sqlalchemy

我已经将带有多个表的postgresql数据库读入SQLAlchemy。

我尝试编写一个执行连接的查询,并对每个" summable"进行求和。柱。我的方法工作正常,但要求我明确键入我想要求的每一列,我有~40。

query = session.query(Table1.c.column1,\
                      Table2.c.columnB,\
                      func.sum(Table2.c.columnC),\
                      func.sum(Table2.c.columnD),\
                      ...
                      # Continue to write columns here
            .join(Table2)\
            .filter(Table1.c.column1 == Table2.c.columnA)\
            .group_by(Table1.c.column1, Table2.c.columnB)\
            .order_by(Table1.c.column1)

我一直在搜索,无法找到一个常见模式的答案,这让我觉得我非常偏离这一点。有没有办法在不必输入每一列的情况下执行此操作?

1 个答案:

答案 0 :(得分:1)

你肯定可以做到这一点,只要你能定义什么是" summable"柱。也许你只能通过列的数据类型或某些命名约定来实现。

无论如何,下面是使用每个表中的简单列表来实现该代码的代码片段。

<强>型号:

# define actual ORM classes, but the code uses actual core `Table`

class Model1(Base):
    __tablename__ = 'table1'

    id = sa.Column(sa.Integer, primary_key=True)

    column1 = sa.Column(sa.String)
    column2 = sa.Column(sa.Numeric)
    column3 = sa.Column(sa.Numeric)

class Model2(Base):
    __tablename__ = 'table2'

    id = sa.Column(sa.Integer, primary_key=True)

    columnA = sa.Column(sa.String)
    columnB = sa.Column(sa.Numeric)
    columnC = sa.Column(sa.Numeric)
    columnD = sa.Column(sa.Numeric)


Table1 = Model1.__table__
Table2 = Model2.__table__

基本查询:

q = (
    session.query(
        Table1.c.column1,
        Table2.c.columnA,  # WHY need this when it is identical to `column1`?
    )
    .join(Table2, Table1.c.column1 == Table2.c.columnA)
    .group_by(
        Table1.c.column1,
        Table2.c.columnB,
    )
    .order_by(
        Table1.c.column1,
    )
)

其他专栏:

summable_columns = {
    Table1: [
        'column2',
        'column3',
    ],
    Table2: [
        'columnC',
        'columnD',
    ],
}

for table, column_names in summable_columns.items():
    for column_name in column_names:
        column = getattr(getattr(table, 'c'), column_name)
        label = 'sum_{table_name}_{column_name}'.format(table_name=table.name, column_name=column_name)
        q = q.add_column(sa.func.sum(column).label(label))

for r in q:
    print(r)

其他栏目(替代方案):

当然,您可以定义一些其他逻辑来扩展查询。以下示例使用类型和排除列表(希望它比包含版本小得多):

def is_summable(column):
    exclude_columns = [
        'id',
        'column1',
        'columnA',
        'columnB',
    ]
    return (
        isinstance(column.type, (sa.Numeric, sa.Float, sa.Integer))
        and column.name not in exclude_columns
    )

for table in (Table1, Table2):
    for column in getattr(table, 'c'):
        label = 'sum_{table_name}_{column_name}'.format(table_name=table.name, column_name=column.name)
        q = q.add_column(sa.func.sum(column).label(label))