Ответ
В SQLAlchemy JOIN-запросы можно выполнять двумя основными способами: через ORM (объектно-реляционное отображение) и через Core (прямое построение SQL-выражений).
1. ORM-подход
Это наиболее распространенный способ при работе с моделями данных. SQLAlchemy автоматически определяет условие соединения, если между моделями настроены отношения (relationship).
Предположим, есть модели User и Address со связью User.addresses.
INNER JOIN
Используется метод .join(). Он соединяет таблицы по настроенному отношению.
from sqlalchemy.orm import sessionmaker
# Найти всех пользователей, у которых есть адрес в Калифорнии
query = session.query(User).join(Address).filter(Address.state == 'CA')
california_users = query.all()
LEFT OUTER JOIN
Используется метод .outerjoin() или join(..., isouter=True). Полезен, когда нужно получить все записи из левой таблицы, даже если для них нет совпадений в правой.
# Найти всех пользователей и их адреса (включая пользователей без адресов)
query = session.query(User, Address).outerjoin(Address)
all_users_with_addresses = query.all()
Жадная загрузка (Eager Loading)
Чтобы избежать проблемы N+1 запросов при доступе к связанным объектам, используйте joinedload.
from sqlalchemy.orm import joinedload
# Загрузить всех пользователей и сразу же их адреса одним запросом
users = session.query(User).options(joinedload(User.addresses)).all()
# Доступ к user.addresses не вызовет дополнительных запросов к БД
for user in users:
for address in user.addresses:
print(user.name, address.email_address)
2. Core-подход
Этот подход ближе к написанию чистого SQL и используется для более сложных или оптимизированных запросов, работая напрямую с объектами Table.
from sqlalchemy import select, text
# users и addresses - это объекты Table
stmt = select(users.c.name, addresses.c.email_address)
.select_from(users.join(addresses, users.c.id == addresses.c.user_id))
.where(users.c.name.like('j%'))
with engine.connect() as connection:
result = connection.execute(stmt)
for row in result:
print(row) Ответ 18+ 🔞
А, SQLAlchemy, блядь! Ну, слушай, тут всё просто, как три копейки, если не заебываться. JOIN-ы, сука, можно делать двумя путями: через их эту, блядь, ORM-магию, где всё само летает, и через Core, где ты сам, как пацан, собираешь SQL из кубиков.
1. ORM-подход (для ленивых и умных)
Это когда ты настраиваешь модели, они там друг за друга держатся, а потом просто говоришь «дай» — и всё прилетает. Представь, есть User и Address, и они уже, блядь, знакомы через relationship.
INNER JOIN (обычный, чтоб не выёбываться)
Используешь .join(). Он сам догадается, за какую ручку их соединить, если ты отношения настроил.
from sqlalchemy.orm import sessionmaker
# Найти всех юзеров, которые живут в Калифорнии (ну, или хотя бы адрес там зарегили)
query = session.query(User).join(Address).filter(Address.state == 'CA')
california_users = query.all()
LEFT OUTER JOIN (чтоб всех подряд, даже лузеров без адреса)
Тут .outerjoin() или join(..., isouter=True). Получишь всех пользователей, даже если они живут в бомжатнике под мостом.
# Всех юзеров и их адреса, включая тех, у кого адрес — это «спроси у мамы»
query = session.query(User, Address).outerjoin(Address)
all_users_with_addresses = query.all()
Жадная загрузка (Eager Loading, чтоб не ебать базу лишними запросами)
А то бывает: достал юзеров, потом полез за адресами — и пошло-поехало, N+1 запрос, сервер плачет. Чтоб такого не было, юзай joinedload.
from sqlalchemy.orm import joinedload
# Одним махом грузим всех юзеров и сразу все их адреса, как мешки с картошкой
users = session.query(User).options(joinedload(User.addresses)).all()
# Теперь можно спокойно итерировать — базу больше не дергаем, она уже выдохлась
for user in users:
for address in user.addresses:
print(user.name, address.email_address)
2. Core-подход (для настоящих пацанов, которые в SQL как рыба в воде)
Тут уже ближе к голому металлу, работаешь прямо с таблицами (Table), без всяких модельных нежностей.
from sqlalchemy import select, text
# users и addresses — это уже не модели, а голые Table-объекты
stmt = select(users.c.name, addresses.c.email_address)
.select_from(users.join(addresses, users.c.id == addresses.c.user_id))
.where(users.c.name.like('j%'))
with engine.connect() as connection:
result = connection.execute(stmt)
for row in result:
print(row)
Вот и вся магия, ёпта. Выбирай, что тебе ближе: ORM — чтобы быстро и с комфортом, или Core — когда надо всё по-взрослому, с контролем над каждым байтом. Главное — не перепутай, а то получишь хуй с горы вместо результата.