简体   繁体   English

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

[英]SQLAlchemy join with subquery and multiple mappers

According to the SQLAlchemy documentation one can do this: 根据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" SQLA文档,“高级定位”部分

What I would want from the query is not the User but a tuple of (User, Address) constructed via a "left outer join" so I get tuples of (User, Address) or (User, None) if the user has no address or the (subquery?) filter removed the address from the users list of addresses if they don't match the filter's criteria. 我从查询中想要的不是用户,而是通过“左外部联接”构造的(User,Address)元组,因此如果用户没有地址,我将得到(User,Address)或(User,None)元组或(子查询?)过滤器从用户地址列表中删除了该地址(如果他们不符合过滤器的条件)。

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

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

I adapted to example to my actual classes, but it does not work. 我将示例改编为实际班级,但没有用。 I have tried with "correlated" and "aliased", but I do find the solution. 我曾尝试使用“相关”和“混淆”,但确实找到了解决方案。 What do I need to change to make it work? 我需要更改使其工作吗?

This would be the SQL I am after: 这将是我追求的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

It would be more clear if you had included the target SQL statement that you wish to execute, but I am assuming you want to query for all the fields in the user along with its address where the the email_address matches some specific value. 如果您已经包含了要执行的目标SQL语句,将会更加清楚,但是我假设您要查询用户中的所有字段以及email_address与某个特定值匹配的地址。 If this is what you want, a simple join will suffice and a subquery can be completely avoided. 如果这是您想要的,那么简单的连接就足够了,可以完全避免子查询。 For sqlalchemy, it is possible to select explicitly from a table using select_from , and that has an example which can probably be adapted to something like so for your specific use case: 对于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 = ?

Which should get back a result with the user along with its address for the given email_address. 哪个应该与用户一起返回结果以及给定email_address的地址。

Of course (as per comments here), since User in this case is in the primary query, the select_from can be omitted for this particular instance, but this is still useful demonstration on how the queries are constructed by sqlalchemy. 当然(根据此处的注释),由于在这种情况下User是在主查询中,因此可以针对此特定实例省略select_from ,但这对于sqlalchemy如何构造查询仍然很有用。


If you want specific columns (originally, you were not clear by what you meant by a tuple of (User, Address), and that implies the entire class which is what is being returned already), simply pass the attribute that you want as documented in the querying section . 如果你想具体列(原来,你是不是你的(用户地址)的元组的意思明确,那意味着整个类,这是被已经返回什么),简单地传递你想要的属性如记录在查询部分

For your intended part, you need to make use of the subquery as the query parameter instead of the Address , and with manual joins as specified again in the tutorial under the Using Subqueries section. 对于您的预期部分,您需要使用子查询作为查询参数,而不是Address ,并使用手动联接,如本教程的“ 使用子查询”部分中再次指定的那样。

The address_subq in your question can be used as is, but if you want to replace your inner query to be more like what you later specified, try: 您问题中的address_subq可以按原样使用,但是如果您要替换内部查询,使其更像您以后指定的内容,请尝试:

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

The final query that satisfies your requirement will be: 满足您要求的最终查询将是:

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

Printing and executing the query (the print output has been modified for readability) 打印并执行查询(已修改打印输出以提高可读性)

>>> print(q)
SELECT users.name AS users_name, anon_1.email_address AS anon_1_email_address 
FROM users LEFT OUTER JOIN (
    SELECT addresses.id AS id,
           addresses.email_address AS email_address,
           addresses.user_id AS user_id 
    FROM addresses 
    WHERE addresses.email_address LIKE ?
) AS anon_1 ON users.id = anon_1.user_id
>>> q.all()
[('ed', 'ed@foo.com'), ('wendy', None), ('mary', None), ('fred', None), ('jack', None)]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM