使用SQLAlchemy表达式语言编写复杂查询

时间:2014-10-29 07:54:51

标签: python sql sqlite sqlalchemy

到目前为止我得到了什么

我有两个相当简单的查询,在SQL

中看起来像这样
SELECT COUNT(known), item FROM log  GROUP BY item
SELECT COUNT(known), item FROM (SELECT known, item FROM log WHERE known == 1) GROUP BY item

对于具有“已知”,“项目”列的表“log”,两个查询都会对行进行计数,每个项目的行数是一个,另一个是每个项目的行数是多少将“已知”字段设置为1的表。这是我直接使用SQLite的程度,并且我还能够将其转换为SQLAlchemy表达式。

目标

我想做一些可能有点复杂的事情。我想将两个查询的结果写入另一个表,可能会覆盖那里的条目。架构看起来有点像这样。

CREATE TABLE fractions (
    id INTEGER NOT NULL, 
    item INTEGER, 
    sum_known_only FLOAT NOT NULL, 
    sum FLOAT NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY(item) REFERENCES items (id), 
)
  • 如何将值输入此表?
  • 这可以通过单个SQL表达式解决吗?我想尽量避免从数据库中获取值然后再将它们放入
  • 如何用sqlalchemy表达式语言表达这样一个复杂的表达式?

  • 奖金将是:我可以使用子查询为每个sum构建sum_known_onlyitem的分数吗?

我很欣赏SQLAlchemy表达式语言(不是ORM)和一般的SQL提示,两者对我都非常有帮助。

1 个答案:

答案 0 :(得分:0)

请注意,我假设(因为该字段为FLOAT)有一个Log.value列,其中包含您实际汇总的值,而不仅仅是进行简单计数(这将是更简单)。

下面的查询应该允许您在一个查询中选择两个值,其余的答案将使用它:

one_select = (
    session
    .query(
        Log.item.label("item"),
        # func.count(Log.item).label("num_all"),
        # func.sum(case([(Log.known == 1, 1)], 0)).label("num_known"),
        func.sum(Log.value).label("sum_all"),
        func.sum(case([(Log.known == 1, Log.value)], 0)).label("sum_known_only")
    )
    .group_by(Log.item)
)

插入新记录非常简单,但为了进行全面更新,我们还需要先删除现有记录,因此功能如下:

def delete_insert():
    """
    First delete from Fraction table, then insert *all* values.
     + rather simple
     - probably not the most efficient for the large table
    """
    session.flush()

    # 1. first delete existing ones
    subq = exists(
        select([1]).where(Log.item == Fraction.item).correlate(Fraction))
    de_ = delete(Fraction).where(subq)
    session.execute(de_)

    # 2. now insert all
    ins = (insert(Fraction).from_select(
        (Fraction.item, Fraction.sum, Fraction.sum_known_only), one_select))
    session.execute(ins)

    session.commit()

还可以创建它的update_insert版本,首先我们更新现有Fraction记录的值,然后插入新记录。但是如果您指定数据库引擎以及构建分数的意思,那么更新会涉及更多,但也很乐意提供它。