Учебники

SQLAlchemy ORM — Работа с объединениями

Теперь, когда у нас есть две таблицы, мы увидим, как создавать запросы для обеих таблиц одновременно. Чтобы создать простое неявное соединение между Customer и Invoice, мы можем использовать Query.filter (), чтобы приравнять их связанные столбцы. Ниже мы сразу загружаем объекты Customer и Invoice, используя этот метод —

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind = engine)
session = Session()

for c, i in session.query(Customer, Invoice).filter(Customer.id == Invoice.custid).all():
   print ("ID: {} Name: {} Invoice No: {} Amount: {}".format(c.id,c.name, i.invno, i.amount))

Выражение SQL, генерируемое SQLAlchemy, выглядит следующим образом:

SELECT customers.id 
AS customers_id, customers.name 
AS customers_name, customers.address 
AS customers_address, customers.email 
AS customers_email, invoices.id 
AS invoices_id, invoices.custid 
AS invoices_custid, invoices.invno 
AS invoices_invno, invoices.amount 
AS invoices_amount
FROM customers, invoices
WHERE customers.id = invoices.custid

И результат приведенных выше строк кода выглядит следующим образом:

ID: 2 Name: Gopal Krishna Invoice No: 10 Amount: 15000
ID: 2 Name: Gopal Krishna Invoice No: 14 Amount: 3850
ID: 3 Name: Govind Pant Invoice No: 3 Amount: 10000
ID: 3 Name: Govind Pant Invoice No: 4 Amount: 5000
ID: 4 Name: Govind Kala Invoice No: 7 Amount: 12000
ID: 4 Name: Govind Kala Invoice No: 8 Amount: 8500
ID: 5 Name: Abdul Rahman Invoice No: 9 Amount: 15000
ID: 5 Name: Abdul Rahman Invoice No: 11 Amount: 6000

Фактический синтаксис SQL JOIN легко достигается с помощью метода Query.join () следующим образом:

session.query(Customer).join(Invoice).filter(Invoice.amount == 8500).all()

Выражение SQL для объединения будет отображаться на консоли —

SELECT customers.id 
AS customers_id, customers.name 
AS customers_name, customers.address 
AS customers_address, customers.email 
AS customers_email
FROM customers JOIN invoices ON customers.id = invoices.custid
WHERE invoices.amount = ?

Мы можем перебрать результат, используя цикл for —

result = session.query(Customer).join(Invoice).filter(Invoice.amount == 8500)
for row in result:
   for inv in row.invoices:
      print (row.id, row.name, inv.invno, inv.amount)

При 8500 в качестве параметра связывания отображается следующий вывод:

4 Govind Kala 8 8500  

Query.join () знает, как соединить эти таблицы, потому что между ними есть только один внешний ключ. Если не было внешних ключей или было больше внешних ключей, Query.join () работает лучше, когда используется одна из следующих форм:

query.join (Счет, id == Address.custid) явное условие
query.join (Customer.invoices) указать отношения слева направо
query.join (Invoice, Customer.invoices) то же самое, с явной целью
query.join ( ‘счета’) то же самое, используя строку

Точно так же функция externaljoin () доступна для достижения внешнего левого соединения.

query.outerjoin(Customer.invoices)

Метод subquery () создает выражение SQL, представляющее инструкцию SELECT, встроенную в псевдоним.

from sqlalchemy.sql import func

stmt = session.query(
   Invoice.custid, func.count('*').label('invoice_count')
).group_by(Invoice.custid).subquery()

Объект stmt будет содержать инструкцию SQL, как показано ниже:

SELECT invoices.custid, count(:count_1) AS invoice_count FROM invoices GROUP BY invoices.custid

Когда у нас есть наше утверждение, оно ведет себя как конструкция таблицы. Столбцы в выражении доступны через атрибут с именем c, как показано в приведенном ниже коде —

for u, count in session.query(Customer, stmt.c.invoice_count).outerjoin(stmt, Customer.id == stmt.c.custid).order_by(Customer.id):
   print(u.name, count)

Вышеуказанный цикл for отображает количество счетов по именам следующим образом: