I`m trying to figure out how to define the join type in sql-alchemy ORM. How to use left join and left outer join? What about inner join?
This is for the query which can select all crm_lead without a related crm_task. I tried exists filter but couldn`t filter existing crm_leads with this clause.
Desired 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);
OR: (if exists clause is better for this case)
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);
My best try was:
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))
)
but it converts into:
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
ALTERNATIVE SOLUTION: My case can be solved with raw SQL as shown here [https://stackoverflow.com/a/22084672/2822537]
Example:
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
})