python - SQLAlchemy:查找数组列之间的差异

标签 python postgresql sqlalchemy

我有一个名为 UnitOfWork 的表,它有 3 列 cases_identifiedcases_completedcases_double_check,所有这些是整数的 Postgresql 数组。

是否可以编写一个查询(或混合属性)来查找已识别但不在已完成或双重检查列中的案例?

这是我想出来的,但是 SQL 表达式不起作用:

@hybrid_property
def todo(self):
    return [x for x in self.cases_identified
            if x not in self.cases_completed and
            x not in self.cases_double_check]

@todo.expression
def todo(cls):
    return [x for x in cls.cases_identified
            if x not in  cls.cases_completed and
            x not in cls.cases_double_check]

我在测试查询中得到的错误是:

test = Session.query(UnitOfWork.todo).first()
NotImplementedError: Operator 'contains' is not supported on this expression

最佳答案

对于这个答案,我假设 cls.cases_identifiedcls.cases_completedcls.cases_double_check 属于 postgresql .ARRAY(Integer) 在 Python 端输入。

您的 @todo.expression 应该只返回:一个 SQL 表达式。目前它正在尝试返回一个 python 列表。自 postgresql.ARRAY 以来引发异常不支持 in 运算符,尽管它有一个方法 contains ,它映射到 Postgresql 中的 @> 运算符并测试“元素是否是参数数组表达式元素的超集”。另一方面,这不是您想要的。你很幸运,你在那里有 if x not in ...,很简单

[x for x in cls.cases_identified]

似乎导致无限循环而不是异常。

获取 Postgresql 中数组之间的差异已涵盖 here广泛,但这里是你如何使用 SQLAlchemy 应用它,首先使用 an array constructor :

from sqlalchemy import func

...

class UnitOfWork(...):

    @todo.expression
    def todo(cls):
        # Force correlation of `cls` from outer FROM objects. Use
        # the `select()` shorthand method of `FunctionElement`.
        identified = func.unnest(cls.cases_identified).select().correlate(cls)
        completed = func.unnest(cls.cases_completed).select().correlate(cls)
        double_check = func.unnest(cls.cases_double_check).select().correlate(cls)
        # Create the subquery statement
        stmt = identified.except_(completed.union(double_check))
        # Uses the `func` generic for ARRAY constructor from
        # subquery syntax. The subquery statement has to be
        # converted to a "scalar subquery" in the eyes of SQLA
        # (really just a subquery returning 1 col) in order
        # to remove it from the FROM clause hierarchy.
        return func.array(stmt.as_scalar())

这有一个不提供任何 FROM 对象的缺点(因为它与封闭查询中的所有内容相关联),因此您必须像这样发出原始查询:

test = Session.query(UnitOfWork.todo).select_from(UnitOfWork).first()

您还可以使用 Postgresql intarray module为无空整数数组提供特殊函数和运算符:

class UnitOfWork(...):

    @todo.expression
    def todo(cls):
        return (cls.cases_identified - cls.cases_completed - 
                cls.cases_double_check)

请注意,您必须先在 Postgresql 中安装扩展:

CREATE EXTENSION intarray;

关于python - SQLAlchemy:查找数组列之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42269201/

相关文章:

python - 如何在 SQLalchemy 中连接同一个表并计算数据

python - 如何告诉 Python 重新导入我的脚本?

sql - 使用查找表和替换函数更新子字符串

python - 在Python中将字典格式的txt文件转换为excel

sql - 楼层时间戳精确到秒

postgresql - 将 varbit 转换为 int 的其他方法?还有大金币?

python - 重复 key 更新上的 SQLAlchemy

python - Flask/SQLAlchemy - 无法正确查询关系

python - 安装 pip install xlwt 时终端出现错误消息

python按空格和换行符拆分字符串