SQLAlchemy ORM selecciona varias entidades de la subconsulta

Necesito consultar varias entidades, algo como session.query(Entity1, Entity2) , solo desde una subconsulta en lugar de hacerlo directamente desde las tablas. Los documentos tienen algo sobre la selección de una entidad de una subconsulta, pero no puedo encontrar la forma de seleccionar más de una, ya sea en los documentos o por experimentación.

Mi caso de uso es que necesito filtrar las tablas subyacentes a las clases asignadas por una función de ventana, que en PostgreSQL solo se puede hacer en una subconsulta o CTE.

EDITAR: la subconsulta abarca una ÚNICA de ambas tablas, por lo que no puedo hacer un aliased(Entity1, subquery) .

 from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class A(Base): __tablename__ = "a" id = Column(Integer, primary_key=True) bs = relationship("B") class B(Base): __tablename__ = "b" id = Column(Integer, primary_key=True) a_id = Column(Integer, ForeignKey('a.id')) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e) s.add_all([A(bs=[B(), B()]), A(bs=[B()])]) s.commit() # with_labels() here is to disambiguate A.id and B.id. # without it, you'd see a warning # "Column 'id' on table being replaced by another column with the same key." subq = s.query(A, B).join(A.bs).with_labels().subquery() # method 1 - select_from() print s.query(A, B).select_from(subq).all() # method 2 - alias them both. "subq" renders # once because FROM objects render based on object # identity. a_alias = aliased(A, subq) b_alias = aliased(B, subq) print s.query(a_alias, b_alias).all() 

Estaba intentando hacer algo como la pregunta original: unir una tabla filtrada con otra tabla filtrada usando una combinación externa. Estaba luchando porque no es del todo obvio cómo:

  • cree una consulta SQLAlchemy que devuelva entidades de ambas tablas. La respuesta de @zzzeek me mostró cómo hacerlo: get_session().query(A, B) .
  • utilizar una consulta como una tabla en dicha consulta. La respuesta de @zzzeek también me mostró cómo hacerlo: filtered_a = aliased(A) .
  • Utilice una unión EXTERNA entre las dos entidades. El uso de select_from() después de la outerjoin() destruye la condición de combinación entre las tablas, lo que resulta en una combinación cruzada. Por la respuesta de @zzzeek, ​​supuse que si a es a alias (), entonces puedes incluir a en la consulta () y también .outerjoin (a), y no se unirá por segunda vez, y parece que funciona.

Siguiendo cualquiera de los enfoques sugeridos por @zzzeek, ​​resultó directamente en una combinación cruzada (explosión combinatoria), porque uno de mis modelos utiliza la herencia, ¡y SQLAlchemy agregó las tablas principales fuera del SELECT interno sin ninguna condición! Creo que esto es un error en SQLAlchemy. El enfoque que adopté al final fue:

 filtered_a = aliased(A, A.query().filter(...)).subquery("filtered_a") filtered_b = aliased(B, B.query().filter(...)).subquery("filtered_b") query = get_session().query(filtered_a, filtered_b) query = query.outerjoin(filtered_b, filtered_a.relation_to_b) query = query.order_by(filtered_a.some_column) for a, b in query: ...