SQLAlchemy与子查询和多个映射器连接

时间:2018-01-19 15:21:50

标签: python sqlalchemy

根据SQLAlchemy文档,可以这样做:

address_subq = session.query(Address).\
            filter(Address.email_address == 'ed@foo.com').\
            subquery()

q = session.query(User).join(address_subq, User.addresses)

SQLA docs, section "Advanced Targeting"

我想从查询中得到的不是用户而是通过“左外连接”构建的(用户,地址)元组,因此如果用户我得到(用户,地址)或(用户,无)的元组没有地址或(子查询?)过滤器从用户地址列表中删除了地址,如果它们与过滤器的标准不匹配。

address_subq = session.query(Address).\
            filter(Address.email_address == 'ed@foo.com').\
            subquery()

q = session.query(User, Address).outerjoin(address_subq, User.addresses)

我适应了我的实际课程的例子,但它不起作用。我试过“相关”和“别名”,但我确实找到了解决方案。我需要更改什么才能使其正常工作?

这将是我追求的SQL:

SELECT
   user.name, addr.email
FROM
   user
      LEFT OUTER JOIN
   (SELECT
      address.name, address.user_id
   FROM
      address
   WHERE
      address.email LIKE '%foo.com%') AS addr ON user.id = addr.user_id

1 个答案:

答案 0 :(得分:1)

如果您已经包含了要执行的目标SQL语句,那将更加清楚,但我假设您要查询用户中的所有字段以及email_address与某个特定值匹配的地址。如果这是你想要的,一个简单的连接就足够了,可以完全避免子查询。对于sqlalchemy,可以使用select_from从表中明确选择,并且有一个示例可以根据您的具体用例进行调整:

>>> q = session.query(User, Address).select_from(User).join(Address).filter(
...     Address.email_address == 'ed@foo.com')
>>> print(q)
SELECT users.id AS users_id, users.name AS users_name, ... 
    addresses.email_address ..., addresses.user_id ...,
FROM users JOIN addresses ON users.id = addresses.user_id 
WHERE addresses.email_address = ?

哪个应该返回给用户的结果以及给定email_address的地址。

当然(根据此处的评论),由于User在这种情况下位于主查询中,因此{1}}可以省略此特定实例,但这仍然是有用的演示如何查询由sqlalchemy构建。

如果你想要特定的列(最初,你不清楚你的(用户,地址)元组是什么意思,并且暗示了已经返回的整个类),只需传递你的属性即可想要as documented in the querying section

对于您想要的部分,您需要使用子查询作为查询参数而不是select_from,并在Using Subqueries部分的教程中再次使用手动连接。

您问题中的Address可以按原样使用,但如果您想将内部查询替换为您稍后指定的内容,请尝试:

address_subq

满足您要求的最终查询将是:

address_subq = session.query(Address).filter(
    Address.email_address.like('%@foo.com')).subquery()

打印并执行查询(打印输出已被修改以便于阅读)

q = session.query(
     User.name, address_subq.c.email_address
).outerjoin(
     address_subq, User.id==address_subq.c.user_id)