How to get orders count sub-queries - mysql

I have some difficuties to get orders count with the following SQL query:
select
d.id,
d.title,
count(distinct o.id)
from store s
left join `order` o on o.store_id = s.id
left join order_product op on op.order_id=o.id
left join store_product sp on sp.id = op.product_id
left join product p on p.id = sp.product_id
left join department_category_to_entity dce1 on dce1.entity_type IN ('Product') and dce1.entity_id = p.id
left join department_category_to_entity dce2 on op.status != 'replaced' and
op.replacement_id is null and
dce2.entity_type IN ('StoreProduct') and
dce2.entity_id = sp.id
left join department_category_to_entity dce3 on op.status = 'replaced' and
op.replacement_id is not null and
dce3.entity_type IN ('StoreProduct') and
dce3.entity_id = op.replacement_id
left join department_category dc on dc.id = p.department_category_id or
dc.id = dce1.category_id or
dc.id = dce2.category_id or
dc.id = dce3.category_id
left join department d on d.id = dc.department_id
where d.id is not null
group by d.id;
Is it possible to get orders count without sub-queries or to get correct count of orders? Please, help... Thank you!

You have LEFT JOIN, which says to keep looking even if there is no row in the 'right' table. But, on the other hand, you are GROUPing BY a column in the last of a chain of LEFT JOINs! Perhaps you meant JOIN instead of LEFT JOIN??
Saying where d.id is not null is roughly equivalent to saying "Oops, all those LEFT JOINs could have been JOINs.
With GROUP BY and JOINs (LEFT or otherwise), you are doing an "inflate-deflate". What logically happens is all the JOINing is done to build a huge intermediate table with all the valid combinations. Then the COUNT(*) and GROUP BY are done. This tends to make the COUNTs (and SUMs, etc) have bigger values than expected.
What's the most direct route to get from department to order? It does not seem to involve store, so get rid of that table.
Are other tables irrelevant?
Even after addressing those issue, you still may be getting the wrong value. Please provide, for starters, `SHOW CREATE TABLE for each table.

Related

mysql distinct query returning more than 1 result

I'm expecting for one product along with it's title and due amount. this query however is not efficient. Not sure with what i'm missing here. Any help would be appreciated
SELECT DISTINCT p.product_title, po.qty, co.due_amount
FROM pending_order po
LEFT JOIN products p ON p.product_id = po.product_id
LEFT JOIN customer_orders co ON po.invoice_no = co.invoice_no
LEFT JOIN customers cs ON cs.customer_id = co.customer_id
WHERE co.invoice_no = '1355021133'
the result i'm getting

Using cases to determine which table should join

I have four tables products, product_histories, vendor_invoices and invoices
This is the query I have developed
SELECT p.product_id, product_name, vendor_name FROM products AS p
INNER JOIN product_histories AS ph ON p.product_id = ph.product_id
CASE
WHEN ph.history_type = "P" THEN
LEFT JOIN vendor_invoices AS vi ON link_id = vi.vi_id
WHEN ph.history_type = "S" THEN
LEFT JOIN invoices AS i ON i.invoice_id = link_id
END
ORDER BY ph_id ASC
What I want that if ph.history_type is P then is should join vendor_invoices and if it is S then it should join invoices. But it says there is a syntax error.
Can anyone help me out with it? Or could show a better way to achieve this problem.

Cartesian join with multple outer joins to common root

I have the following schema.
I can run two queries fairly simply
select * from booking_model_assignment
join booking_model on booking_model_assignment.booking_model_id = booking_model.id
left outer join axis_channel_mappings on bmi_id = axis_channel_mappings.assignment_id
left outer join axis_revenue_stream_mappings on bmi_id = axis_revenue_stream_mappings.assignment_id
which will give me all of the combinations of channel mappings and 'revenue_stream_mappings' which fit a booking model, with Null if there is one which only matches in one of the tables.
The other query
select * from axis_channel join axis_revenue_stream
Gives all of the possible combinations of channels and revenue streams.
What I would like is a query which will give all of the combinations, and the booking_model if that combination matches.
Any time I try to join or subquery I seem to get too many, or too few results. I think the issue is that I want the assignment_id to match across outer joins but only if there is an outer join.
The schema is laid out like this so it will be possible to add new axis and fit models to combinations, so if there is an easier way to achieve this I would be open to changing the schema.
EDIT
I have a partial solution based on Eggyal's answer but it is not extendable.
SELECT c.*, r.*, GROUP_CONCAT(a.bmi_id), GROUP_CONCAT(b.name) AS booking_models
FROM axis_channel c
CROSS JOIN axis_revenue_stream r
LEFT JOIN axis_channel_mappings cm ON cm.channel_id = c.id
LEFT JOIN axis_revenue_stream_mappings rm ON rm.revenue_stream_id = r.id
LEFT JOIN booking_model_assignment a ON (a.bmi_id = cm.assignment_id
AND a.bmi_id = rm.assignment_id)
OR (a.bmi_id = cm.assignment_id
AND rm.assignment_id IS NULL)
OR (cm.assignment_id IS NULL
AND a.bmi_id = cm.assignment_id)
LEFT JOIN booking_model b ON b.id = a.booking_model_id
GROUP BY c.id, r.id
But if I were to add more axes this query would grow way to cumbersome.
SELECT c.*, r.*, GROUP_CONCAT(b.name) AS booking_models
FROM axis_channel c
CROSS JOIN axis_revenue_stream r
LEFT JOIN axis_channel_mappings cm ON cm.channel_id = c.id
LEFT JOIN axis_revenue_stream_mappings rm ON rm.revenue_stream_id = r.id
LEFT JOIN booking_model_assignment a ON a.bmi_id = cm.assignment_id
AND a.bmi_id = rm.assignment_id
LEFT JOIN booking_model b ON b.id = a.booking_model_id
GROUP BY c.id, r.id

MySQL query, dealing with active and inactive products

Facing a problem and not getting the hint for a few hours. Maybe onyone can help me out.
Have the following query which shows the Topsellers. So the status of the product (active or not) is saved in b.Article_Status (0=inactive, 1=active).
How do I get the products of the result list which have no active product in the productfamily at the moment. But the product shall still be shown if an old one was ordered (and so is in table order_items) is now inactive and the active one was not ordered yet.
Actual query looks as follow. Already fund a solution which works when the actual active product has been ordered once, but still the problem with the mentioned case.
SELECT count( a.order_itemid ) AS numOrders, c.Product_ID, c.Product_Name, d.producer_name
FROM order_items a
LEFT OUTER JOIN product_article b ON b.Article_ID = a.order_itemid
LEFT OUTER JOIN product c ON b.Article_Productid = c.Product_ID
LEFT OUTER JOIN producer d ON c.Product_Producer = d.producer_id
GROUP BY c.Product_ID
ORDER BY `numOrders` DESC
Solution was a WHERE EXISTS subquery
SELECT count( a.order_itemid ) AS numOrders, c.Product_ID, c.Product_Name, d.producer_name
FROM order_items a
LEFT OUTER JOIN product_article b ON b.Article_ID = a.order_itemid
LEFT OUTER JOIN product c ON b.Article_Productid = c.Product_ID
LEFT OUTER JOIN producer d ON c.Product_Producer = d.producer_id
WHERE EXISTS (SELECT * FROM product_article x WHERE c.Product_ID = x.Article_Productid AND x.Article_Status = 1)
GROUP BY c.Product_ID
ORDER BY `numOrders` DESC
LIMIT 5

Left Join Show All Rows

SELECT
CH.ChannelName, COUNT(O.OrderID) AS Orders
FROM
Channels CH
LEFT JOIN Programs P USING (ChannelID)
LEFT JOIN Codes C USING (ProgramID)
LEFT JOIN Order O USING (CodeID)
WHERE
O.OrderDate = '2012-04-11'
GROUP BY
CH.ChannelName
WITH ROLLUP
This query is only returning channels that have orders. How do I display ALL channels, even if there are no orders in the order table for that particular channel? So basically, all channels will be listed, and if there are no orders for that channel, I need to display zero.
I know the solution to this is probably very simple. Thanks for the help.
SELECT
CH.ChannelName, COUNT(O.OrderID) AS Orders
FROM
Channels CH
LEFT JOIN Programs P USING (ChannelID)
LEFT JOIN Codes C USING (ProgramID)
LEFT OUTER JOIN Order O USING (CodeID)
WHERE
O.OrderDate = '2012-04-11'
GROUP BY
CH.ChannelName
WITH ROLLUP
Try this:
SELECT CH.ChannelName, SUM(O.OrderDate = '2012-04-11') AS Orders
FROM Channels CH
LEFT JOIN Programs P USING (ChannelID)
LEFT JOIN Codes C USING (ProgramID)
LEFT JOIN Order O USING (CodeID)
GROUP BY CH.ChannelName
WITH ROLLUP
Your where-clause limits the query to the channels that have orders for that date, but if you move that condition into the join statement it will give you the result you want:
SELECT
CH.ChannelName, COUNT(O.ID) AS Orders
FROM
Channels CH
LEFT JOIN Programs P USING (ChannelID)
LEFT JOIN Codes C USING (ProgramID)
LEFT JOIN Order O ON CH.CodeID = O.CodeID AND O.OrderDate = '2012-04-11'
GROUP BY
CH.ChannelName
WITH ROLLUP
Note, that it should be COUNT(O.ID) to make SQL count only rows with non-null orders. In that case you'll correctly get zero orders count for channels without orders.