Я пытаюсь выяснить, как определить тип соединения в sql-алхимии ORM. Как использовать левое соединение и левое внешнее соединение? А как насчет внутреннего соединения?
Это для запроса, который может выбрать все crm_lead без связанной с ним crm_task. Я пробовал существующий фильтр, но не смог отфильтровать существующие crm_leads с этим условием.
Требуемый SQL:
select *
from crm_lead l
join crm_task t on l.id = t.lead_id
left outer join crm_pipeline_status cps on l.pipeline_status_id = cps.id
where l.pipeline_status_id not in (142, 143)
and (t.id is null or t.is_completed is false);
ИЛИ: (если существует предложение, лучше для этого случая)
select *
from crm_lead l
left outer join crm_pipeline_status cps on l.pipeline_status_id = cps.id
where cps.crm_id not in (142, 143)
and not exists (select id from crm_task t where l.id = t.lead_id and t.is_completed is false);
Моя лучшая попытка была:
session = sessionmaker(bind=engine, autocommit=True)()
with session.begin():
leads = session.query(CrmLead).outerjoin(CrmTask).outerjoin(CrmPipelineStatus).filter(
and_(CrmLead.account_id == 2,
CrmPipelineStatus.crm_id not in (142, 143),
or_(CrmTask.is_completed is False, CrmTask.id is None))
)
но оно преобразуется в:
SELECT *
FROM crm_lead
LEFT OUTER JOIN crm_task ON crm_lead.id = crm_task.lead_id
LEFT OUTER JOIN crm_pipeline_status ON crm_pipeline_status.id = crm_lead.pipeline_status_id
WHERE false
АЛЬТЕРНАТИВНОЕ РЕШЕНИЕ:
Мой случай может быть решен с помощью необработанного SQL, как показано здесь [https://stackoverflow.com/a/22084672/2822537]
Пример:
query_text = '''
select *
from crm_lead l
left outer join crm_pipeline_status cps on l.pipeline_status_id = cps.id
where cps.crm_id not in (:success_final_status, :failed_final_status)
and l.account_id = :account_id
and not exists (select id from crm_task t where l.id = t.lead_id and t.is_completed is false);
'''
leads = session.execute(query_text, {
'account_id': crm_configuration["instance_id"],
'success_final_status': 142,
'failed_final_status': 143
})