Я использую SQLAlchemy с Pyramid. Я пытаюсь выполнить запрос с пользовательским условием соединения:

DBSession.query(A)\
        .outerjoin(A.b, B.a_id == A.id)\
        .all();

Однако запрос не может выполнить следующую ошибку:

AttributeError: Ни объект «BinaryExpression», ни объект «Comparator» не имеют атрибута «выбираемый»

Проблема проистекает из условия, как будто я его удаляю, запрос работает:

DBSession.query(A)\
        .outerjoin(A.b)\
        .all();

Я не понимаю проблему, поскольку следую синтаксису, описанному в документация:

q = session.query (Пользователь) .join (Адрес, User.id == Address.user_id)

Кто-нибудь видит, что происходит?

11
Eino Gourdin 15 Дек 2015 в 16:50

3 ответа

Лучший ответ

Хорошо, я видел это. Если вы добавите пользовательское условие, синтаксис будет не .outerjoin(A.b, ...), а .outerjoin(B, ...)

Они должны принять оба, на самом деле

(и сообщение об ошибке может быть немного более явным)

14
Eino Gourdin 15 Дек 2015 в 13:55

Другая возможная причина этой ошибки - неправильное использование явного предложения ON для join(): явное предложение ON должно быть одним выражением. Итак, если вы хотите использовать несколько фильтров в предложении ON, их следует объединить с and_ / or_. Например, если вы хотите добавить в условие ON дополнительное условие для объединения:

query(A).join(B, A.b_id = B.id, A.x > N)  # WRONG!
query(A).join(B, and_(A.b_id = B.id, A.x > N))  # CORRECT

Query.join () документ SQLA API сам по себе очень подробный, но несколько суммированный (в нем говорится, что join(*args, **kwargs) не очень помогает). Вот краткое описание некоторых правильных возможных вариантов использования Query.join():

# declare the join using own field which leads to the related object:
query(A).join(A.b)


# declare the join using a class of the related mapper:
query(A).join(B)


# same as above (using related mapper class) but use explicit ON clause
# ON clause can be any/"complex" expression
query(A).join(B, A.b_id = B.id)
query(A).join(B, _and(A.b_id = B.id, ...))


# reverse the order of the join (useful to do a right outer join for example):
query(A).select_entity_from(B).join(A, isouter=True)

Во всех приведенных выше примерах, кроме первого:

  • с явным предложением ON и A, и B могут быть не только классами сопоставления, но и чем-либо «выбираемым»: subquery(), экземпляром Table или псевдонимом ({{ X4}}) подойдет.
  • без явного предложения ON A и B могут быть только классом отображения или экземпляром Table
0
Timur 24 Янв 2019 в 15:00

Еще один способ сказать, что если вы уже указали отношение через .outerjoin(A.b..., вам больше не нужно указывать условие, и фактически вы не можете выполнить и то, и другое.

0
naomiajacobs 20 Дек 2018 в 18:30