Reputation: 514
So here is my simplified structure: Company <- User <- Order <- Order status
I need to perform multiple counts of orders for each company. Each count can have its own filters by order_status
. In return should be company's id and multiple counts.
Here is what I tried for one count, but I cannot combine it with others counts.
SELECT c.id as company_id, COUNT(o.id) as orders_count_total
FROM companies c
LEFT JOIN users u
ON u.belongs_to_company_id = c.id
LEFT JOIN orders o
ON
c.id = o.users_company_id OR
(
u.id = o.users_id AND
u.belongs_to_company_id = c.id AND
o.users_company_id is NULL
)
JOIN orders_orderstatus o_status
ON o.status_id = o_status.id AND NOT (o_status.slug IN ('slug1', 'slug2'))
GROUP BY company_id
Also in this case I miss all companies that don't have any orders
Upvotes: 1
Views: 70
Reputation: 16407
I'm completely unsure of myself on this, so I have my finger on the "Delete" key prepared to nuke this answer if it's completely wrong, but can you do two left joins, one with each condition, and then coalesce?
SELECT
c.id as company_id, COUNT(coalesce (o1.id, o2.id)) as orders_count_total
FROM
companies c
LEFT JOIN users u
ON u.belongs_to_company_id = c.id
LEFT JOIN orders o1
ON c.id = o1.users_company_id
left join orders o2 on
u.id = o2.users_id AND
u.belongs_to_company_id = c.id AND
o2.users_company_id is NULL
JOIN orders_orderstatus o_status
ON coalesce (o1.status_id, o2.status_id) = o_status.id AND
NOT (o_status.slug IN ('slug1', 'slug2'))
GROUP BY company_id
Count should only count non-null results, so I would think this would work.
If not, how about the same coalesce in a CTE and then an inner join to the order status table?
with orders as (
SELECT
c.id as company_id, coalesce (o1.id, o2.id) as order_id
FROM
companies c
LEFT JOIN users u
ON u.belongs_to_company_id = c.id
LEFT JOIN orders o1
ON c.id = o1.users_company_id
left join orders o2 on
u.id = o2.users_id AND
u.belongs_to_company_id = c.id AND
o2.users_company_id is NULL
where
o1.id is not null or o2.id is not null
)
select
o.company_id, count (o.order_id) as orders_count_total
from
orders o
JOIN orders_orderstatus o_status on
o.order_id = o_status.id AND
NOT (o_status.slug IN ('slug1', 'slug2'))
GROUP BY company_id
I've had really bad experience with using "OR" conditions in the join, unless the original condition is highly selective -- yours doesn't appear to be, as you seem to want two completely distinct joins.
Upvotes: 1
Reputation: 1271151
One problem is that the last JOIN
is an inner join. Once you use LEFT JOIN
, you should continue with LEFT JOIN
:
SELECT c.id as company_id, COUNT(o.id) as orders_count_total
FROM companies c LEFT JOIN
users u
ON u.belongs_to_company_id = c.id
orders o LEFT JOIN
ON c.id = o.users_company_id OR
(u.id = o.users_id AND
u.belongs_to_company_id = c.id AND
o.users_company_id is NULL
) LEFT JOIN
orders_orderstatus o_status
ON o.status_id = o_status.id AND
o_status.slug NOT IN ('slug1', 'slug2')
GROUP BY company_id;
Upvotes: 0