Left Join Show All Rows - mysql

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.

Related

Joining 4 tables in mySQL and including NULL values

I am trying to list all customers’ names with each product that customer has ordered and include customers who don't have an order. Also If a customer has ordered the same product multiple times, only list the product once for that customer.
I have the beginning of the query set up so its showing all customers and each product ordered but I can't seem to figure out how to add customers with NULL value ( meaning they haven't ordered an item.) I know left outer join is supposed to be used somehow. This is what I have so far:
select distinct
c.customerName, p.productName
from
products p, customers c, orders o, orderDetails d
left join
When using a left join a syntax like:
select distinct
c.customerName, p.productName
from customers c
left join order o on c.id = o.customer_id
left join orderDetails d on o.id = d.order_id
left join products p on p.id = d.product_id AND
p.productName = 'cow'

How to get orders count sub-queries

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.

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.

Fetching a price with INNER JOIN using 3 different variables

What I have been trying to achieve is to pull a price based on 3 different variables: brand_id, model_id, motor_id.
The design of the tables that I am working with:
The only issue is that when I add an INNER JOIN for databaseapp_lkp_prices I get a zero result set (fyi, there aren't any prices currently set so databaseapp_lkp_prices is an empty table)
I was expecting to see NULL in place of the price for the 48,000 records that exist when I don't add the databaseapp_lkp_prices INNER JOIN
My query is:
SELECT
a.brand,
b.model,
c.motor,
d.ecu_hardware_ver,
d.ecu_software_ver,
d.ecu_software_upg_ver,
d.ecu_brand,
d.ecu_type,
d.eprom,
d.eprom_desc,
d.`checksum`,
d.checksum16,
c.motor_hp * 1.2 AS motor_hp,
e.price,
c.motor_id,
c.model_id,
c.brand_id
FROM
databaseapp_brand AS a
INNER JOIN databaseapp_model AS b ON b.brand_id = a.brand_id
INNER JOIN databaseapp_motor AS c ON b.model_id = c.model_id
INNER JOIN databaseapp_ecu AS d ON d.motor_id = c.motor_id
INNER JOIN databaseapp_lkp_prices AS e ON c.brand_id = e.brand_id AND c.model_id = e.model_id AND c.motor_id = e.motor_id
ORDER BY
a.brand ASC,
b.model ASC
Anyone able to help me out with why I'm getting a zero result set when I try to look up the price.
Cheers!
Inner join requires match. No match no row. You should try LEFT JOIN instead of INNER JOIN for databaseapp_lkp_prices contribution.

Mysql left/inner join combination not working as expected

I am trying to list product variations with their quantities ordered, BUT ALSO show the product variations where there is no quantity ordered. So I thought it would be as simple as selecting the products and doing a left join on the orders of each product where the order is a current revision.
So I expected like this order of operations:
SELECT p.product_id, SUM(po.quantity)
FROM `products` p
LEFT JOIN `product_orders` po ON p.product_id=po.product_id
LEFT JOIN `orders` o ON o.order_id=po.order_id AND o.is_current='1'
but that is getting also the quantities where the is_current is not 1
Then I thought, okay, I can just do an inner join after the left join instead like this:
SELECT p.product_id, SUM(po.quantity)
FROM `products` p
LEFT JOIN `product_orders` po ON p.product_id=po.product_id
INNER JOIN `orders` o ON o.order_id=po.order_id AND o.is_current='1'
but then the products which have not been ordered yet are not being listed. I expected them to to show up as SUM(quantity) being NULL.
Can anyone see where my logic has gone wrong?
Thanks!
Scott
While Kaj's answer is correct, it's not necessarily ideal, as MySQL tends to skip the utilization of indexes when using derived tables (sub-selects). At least, this is my understanding. You can continue to use your methodology of using JOINS if you place the joins within parenthesis:
SELECT p.product_id, SUM(po.quantity)
FROM `products` p
LEFT JOIN (`product_orders` po
INNER JOIN `orders` o ON o.order_id=po.order_id AND o.is_current='1')
ON p.product_id=po.product_id;
Just remember that the ON clause for the LEFT JOIN needs to come after the parenthesis. I hope this helps!
If the only product orders that count are those where it is current then you need to find that subset before you do a left join to it. Otherwise if you do a left join you either get all or only those ordered as you've discovered.
So something like the following should work:
select p.productid, sum(po.quantity)
from products p
left outer join (select po.productid, po.quantity
from productorders po
inner join orders o on o.orderid = po.orderid and o.iscurrent = 1) po on po.productid = p.productid
group by p.productid
Try grouping by your product id:
SELECT p.product_id, SUM(po.quantity)
FROM `products` p
LEFT JOIN `product_orders` po ON p.product_id=po.product_id
INNER JOIN `orders` o ON o.order_id=po.order_id AND o.is_current='1'
GROUP BY p.product_id