LEFT/RIGHT JOIN not returning empty row - mysql

I have a query which uses a self join on 2 tables to return a single row of results. The problem I have is that if seat1 is empty, I don't get anything returned.
SELECT seat1.seat_type_id
, seat1.seat_type_qty
, seat2.seat_type_id
, seat2.seat_type_qty
FROM jos_sv_apptpro2_requests AS R
LEFT JOIN jos_sv_apptpro2_seat_counts AS seat1 ON R.id_requests = seat1.request_id
LEFT JOIN jos_sv_apptpro2_seat_counts AS seat2 ON R.id_requests = seat2.request_id
WHERE (seat1.seat_type_id = 6 AND seat2.seat_type_id = 7)
AND R.id_requests = 8703
AND R.resource = 3
This should return:
seat_type_id 6
seat_type_qty 0 <= this is the empty row
seat_type_id1 7
seat_type_qty 1

WHERE seat1.seat_type_id = 6 AND seat2.seat_type_id = 7
is what removes all rows with NULL values. You should move those condition to the JOIN criteria so that the RDBMS does what you are expecting:
LEFT JOIN jos_sv_apptpro2_seat_counts AS seat1 ON R.id_requests = seat1.request_id
AND seat1.seat_type_id = 6
LEFT JOIN jos_sv_apptpro2_seat_counts AS seat2 ON R.id_requests = seat2.request_id
AND seat2.seat_type_id = 7

Move your where clauses into the JOINs:
LEFT JOIN jos_sv_apptpro2_seat_counts AS seat1
ON (R.id_requests = seat1.request_id) AND (seat1.seat_type_id = 6)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
when you have them in the where clause, you're matching against the whole row. Doing it in the JOIN will do the filtering only on the particular records being joined.

Related

MySQL: From sub query to a single query

I have this query which i believe can be optimized:
SELECT floors.id, floors.floor FROM floors
WHERE floors.societies_id = 1
AND floors.status = 'Y'
AND floors.id NOT IN (
SELECT DISTINCT(floors.id) FROM floors
INNER JOIN societies ON societies.id = floors.societies_id
INNER JOIN resident_floors ON resident_floors.floors_id = floors.id
WHERE societies.id = 1
AND floors.status = 'Y'
)
Is this query fine to use or there it can be improved..?
It looks like you want to get all floors that aren't present in resident_floors. For this we can left join RF in and ask for only rows where the join failed resulting in a null in RF:
SELECT floors.* FROM floors
INNER JOIN societies ON societies.id = floors.societies_id
LEFT JOIN resident_floors ON resident_floors.floors_id = floors.id
WHERE societies.id = 1
AND floors.status = 'Y'
AND resident_floors.floors_id IS NULL

Counting groups of 3? Possible?

I have the following query that is selecting groups of entries of 3 that match and don't exist in the second table.
I need to find a way to return via 'count_result' the count of the number of groups found, not individual entry ids as below.
How can I achieve this?
SELECT COUNT(sub.entry_id) as count_result
FROM exp_submissions AS sub
LEFT JOIN exp_judging_portfolios AS jud1 ON sub.entry_id = jud1.entry_id_1
LEFT JOIN exp_judging_portfolios AS jud2 ON sub.entry_id = jud1.entry_id_2
LEFT JOIN exp_judging_portfolios AS jud3 ON sub.entry_id = jud1.entry_id_3
WHERE jud1.entry_id_1 IS NULL
AND jud2.entry_id_2 IS NULL
AND jud3.entry_id_3 IS NULL
AND sub.member_group = 6
AND sub.type_id = 1
GROUP BY sub.member_id, sub.portfolio_number
HAVING count(sub.portfolio_number) = 3
No subquery necessary.
SELECT COUNT(DISTINCT(sub.member_id, sub.portfolio_number)) as count_result
FROM exp_submissions AS sub
LEFT JOIN exp_judging_portfolios AS jud1 ON sub.entry_id = jud1.entry_id_1
LEFT JOIN exp_judging_portfolios AS jud2 ON sub.entry_id = jud1.entry_id_2
LEFT JOIN exp_judging_portfolios AS jud3 ON sub.entry_id = jud1.entry_id_3
WHERE jud1.entry_id_1 IS NULL
AND jud2.entry_id_2 IS NULL
AND jud3.entry_id_3 IS NULL
AND sub.member_group = 6
AND sub.type_id = 1
GROUP BY sub.member_id, sub.portfolio_number
HAVING count(sub.portfolio_number) = 3
Use your query as the source for another query that just counts the results:
SELECT COUNT(*) FROM (
-- YOUR QUERY GOES HERE --
) AS t

using joins together with aggregates, and retrieving rows when no aggregate exists

The following query on my MySQL tables returns rows from the purchaseorder table that have corresponding entries in the deliveryorder table. How do I construct this query so that I get rows from the purchaseorder table even if no corresponding rows exist in the deliveryorder table? If the users want to see sql table CREATE statements, I can post those, but I'm not posting now as it really makes the question too big.
SELECT
`purchaseorder`.`id` AS `po_id`,
`purchaseorder`.`order_quantity` AS `po_order_quantity`,
`purchaseorder`.`applicable_approved_unit_rate` AS `po_unit_rate`,
`purchaseorder`.`applicable_sales_tax_rate` AS `po_tax_rate`,
`purchaseorder`.`order_date` AS `po_order_date`,
`purchaseorder`.`remarks` AS `po_remarks`,
`purchaseorder`.`is_open` AS `po_is_open`,
`purchaseorder`.`is_active` AS `po_is_active`,
`purchaseorder`.`approved_rate_id` AS `po_app_rate_id`,
`supplier`.`name` AS `sup_name`,
SUM(`deliveryorder`.`quantity`) AS `total_ordered`
FROM `purchaseorder`
LEFT JOIN `deliveryorder` ON (`deliveryorder`.`purchase_order_id` = `purchaseorder`.`id`)
INNER JOIN `approvedrate` ON (`purchaseorder`.`approved_rate_id` = `approvedrate`.`id`)
INNER JOIN `supplier` ON (`approvedrate`.`supplier_id` = `supplier`.`id`)
WHERE (
`purchaseorder`.`is_active` = 1
AND `purchaseorder`.`is_open` = 1
AND `deliveryorder`.`is_active` = 1
AND `approvedrate`.`material_id` = 2
)
HAVING `purchaseorder`.`order_quantity` >= `total_ordered` + 1
You have an aggregating function but no GROUP BY clause, which is wierd, but anyway - something like this? Oops - edited...
SELECT po.id po_id
, po.order_quantity po_order_quantity
, po.applicable_approved_unit_rate po_unit_rate
, po.applicable_sales_tax_rate po_tax_rate
, po.order_date po_order_date
, po.remarks po_remarks
, po.is_open po_is_open
, po.is_active po_is_active
, po.approved_rate_id po_app_rate_id
, s.name sup_name
, SUM(do.quantity) total_ordered
FROM purchaseorder po
LEFT
JOIN deliveryorder do
ON do.purchase_order_id = po.
AND do.is_active = 1
LEFT
JOIN approvedrate ar
ON ar.id = po.approved_rate_id
AND ar.material_id = 2
LEFT
JOIN supplier s
ON s.id = ar.supplier_id
WHERE po.is_active = 1
AND po.is_open = 1
HAVING po.order_quantity >= total_ordered + 1
I couldn't work out how to get the desired results all in one query, but ended up using the following two queries to fulfill my requirements: -
1st query
SELECT
pot.`id` AS `po_id`,
pot.`order_quantity` AS `po_order_quantity`,
pot.`applicable_approved_unit_rate` AS `po_unit_rate`,
pot.`applicable_sales_tax_rate` AS `po_tax_rate`,
pot.`is_open` AS `po_is_open`,
pot.`is_active` AS `po_is_active`,
st.`id` AS `sup_id`,
st.`name` AS `sup_name`,
SUM(dot.`quantity`) AS `total_ordered`
FROM `purchaseorder` pot
INNER JOIN `deliveryorder` dot ON (dot.`purchase_order_id` = pot.`id`)
INNER JOIN `approvedrate` art ON (pot.`approved_rate_id` = art.`id`)
INNER JOIN `supplier` st ON (art.`supplier_id` = st.`id`)
WHERE (
pot.`is_active` = 1
AND pot.`is_open` = 1
AND art.`material_id` = #materialid
AND art.`in_effect` = 1
AND art.`is_active` = 1
AND dot.`is_active` = 1
AND st.`is_active` = 1
)
HAVING pot.`order_quantity` >= `total_ordered` + #materialquantity
2nd query
SELECT
pot.`id` AS `po_id`,
pot.`order_quantity` AS `po_order_quantity`,
pot.`applicable_approved_unit_rate` AS `po_unit_rate`,
pot.`applicable_sales_tax_rate` AS `po_tax_rate`,
pot.`is_open` AS `po_is_open`,
pot.`is_active` AS `po_is_active`,
st.`id` AS `sup_id`,
st.`name` AS `sup_name`,
0 AS `total_ordered`
FROM `purchaseorder` pot
INNER JOIN `approvedrate` art ON (pot.`approved_rate_id` = art.`id`)
INNER JOIN `supplier` st ON (art.`supplier_id` = st.`id`)
WHERE (
pot.`is_active` = 1
AND pot.`is_open` = 1
AND art.`material_id` = #materialid
AND art.`in_effect` = 1
AND art.`is_active` = 1
AND st.`is_active` = 1
AND pot.`order_quantity` >= #materialquantity
AND pot.`id` NOT IN
(
SELECT dot.`purchase_order_id`
FROM `deliveryorder` dot
WHERE dot.is_active = 1
)
)

mysql Left join, mysql does an inner join?

I want to do a left join but mysql just does an inner join?
whats wrong with my query?
select av.*, ap.*
from tbl_available av
left join tbl_appointment ap
on av.avHours = ap.appointmenttime
where av.avCalendarId = 2
and (ap.calendarid = 2 or ap.calendarid= null)
and (ap.appointmentdate = "2012-10-01" or ap.appointmentdate = null)
and av.avDays = DayOfweek("2012-10-01")
order by avHours
mysql only gives those avHours who have a corresponding appointment
Thanks in advance!
Because of these conditions:
and ap.calendarid = 2
and ap.appointmentdate = "2012-10-01"
you only select rows from tbl_appointment which are not null.
If that's what you want - move them to the left join's ON part

MySQL join only selected rows

SELECT invoices.number_formatted, SUM(invoices_elements.netto)
FROM invoices
LEFT JOIN invoices_elements ON invoices_elements_code_invoices_id = invoices_id
WHERE invoices_enable = 1
AND invoices_elements_enable = 1
GROUP BY invoices_elements_code_invoices_id
If table "invoices_elements" doesn't have any rows with "invoices_elements_enable = 1" this query return NULL - but i want "number formatted". So i do this:
SELECT SUM(netto)
FROM (invoices)
LEFT JOIN (SELECT * FROM invoices_elements WHERE invoices_elements_enable = 1) ON invoices_elements_code_invoices_id = invoices_id
WHERE invoices_enable = 1
GROUP BY invoices_elements_code_invoices_id
... and this of coz works. But - is better way to do it?
You can do
SELECT SUM(netto)
FROM invoices
LEFT JOIN invoices_elements
ON invoices_elements_code_invoices_id = invoices_id
AND invoices_elements_enable = 1
WHERE invoices_enable = 1
GROUP BY invoices_elements_code_invoices_id
Note the restriction invoices_elements_enable = 1 is in the ON clause to avoid converting the query into an inner join.