在SQLAlchemy中按复合字段过滤

时间:2016-11-25 02:01:49

标签: sqlalchemy

如何使用SQLAlchemy的ORM按多个字段进行过滤?

示例:

SELECT p.* FROM product p
WHERE (p.barcode, p.partner) NOT IN (
    SELECT barcode, partner
    FROM unallowed_products
);

2 个答案:

答案 0 :(得分:1)

在查看可能的解决方案之前,让我们定义一些别名以减少冗长:

P, U = Product, UnallowedProduct

version-1:OUTER JOIN + WHERE IS NULL

这是非常通用的解决方案,应该适用于所有后端(RDBMS)

q = (
    session.query(P)
    .outerjoin(U, and_(P.barcode == U.barcode, P.partner == U.partner))
    .filter(U.id == None)
)

版本-2:元组比较

这不适用于所有后端,但应该适用于mySQL,postgresql 见tuple_ documentation

q = (
    session.query(P)
    .filter(~tuple_(P.barcode, P.partner).in_(
        select([U.barcode, U.partner])
    ))
)

版本-3:使用多个OR语句

this answer。 没有理由使用它作为版本1和版本-2更清洁。

版本-4:将条形码和合作伙伴连接到一个

this question。 这基本上是你自己的解决方案。 同样,没有理由使用它,因为其他版本更清晰,并且不需要转换为字符串等。

答案 1 :(得分:0)

此查询应该可以解决问题:

SELECT p.* FROM product p
WHERE (p.barcode || "_" || p.partner) NOT IN (
    SELECT barcode || "_" || partner
    FROM unallowed_products
);

可以像这样翻译成SQLAlchemy ORM:

subquery = session.query(
    cast(UnallowedProducts.barcode, type_=Text) +
    '_' +
    cast(UnallowedProducts.partner, type_=Text)
).subquery()

session.query(Product)\
    .filter((
              cast(Product.id, type_=Text) +
              '_' +
              cast(Product.partner, type_=Text)
            ).notin_(subquery))

这个棘手的解决方案几乎适用于所有情况。