Left Join not returning all rows - mysql

I have this query in MySQL:
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT OUTER JOIN `jos_hp_properties2` pr7 ON pr7.property=pr.id
WHERE pr7.field=23
The jos_hp_properties table has 27 rows but the query only returns one. Based on this question I think it may be because of the WHERE clause. The jos_hp_properties2 table has fields id, property, field, value, where field is a foreign key to a third table (which I don't need to get data from).
Is there a way to select all the rows from the first table, including the value from table #2 where the field is 23 (or NULL if there is no field 23)?

Sure. Move the WHERE condition to the JOIN:
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT JOIN `jos_hp_properties2` pr7
ON pr7.property=pr.id
AND
pr7.field=23

You must place the pr7 criteria in the join, not in the where clause. The where clause works on the entire result set AFTER the join has been performed.
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT OUTER JOIN `jos_hp_properties2` pr7 ON pr7.property=pr.id and pr7.field=23

Try this:
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT OUTER JOIN `jos_hp_properties2` pr7 ON pr7.property=pr.id
WHERE (pr7.field=23 OR pr7.field is null)

You can also use a CTE (Common Table Expression) to do the select, then use the CTE to do the left join..
wrc (parentid, childid) as (
select parentid, childid
from placechild
where relationshipid in (select id from placerelationship where relationship = 'Winter Region Capital')
),
stw (cnid, coid, capid, st_or_te, sid, scid,wcid) as (
select s.cnid, s.coid, s.capid, s.st_or_te, s.sid, s.scid, w.childid
from stcap s
left join wrc w
on s.sid = w.parentid
)
select * from stw

Related

Get results from second table joined even if the initial select fails and vice versa

I am using the SELECT statement below to join the property table with the epc table. Not always is the EPC available for a property. I also want the epc table if the property does not exist.
SELECT p.dateAdded, p.paon, p.saon, p.street, p.locality, p.townCity, p.district, p.county, p.propertyType,
p.propertyType, p.oldNew, p.postcode, p.tenure, p.ppd, p.bedrooms, p.bathrooms, p.receptions, p.lastSalePrice, p.lastTransferDate,
e.INSPECTION_DATE, e.TOTAL_FLOOR_AREA, e.CURRENT_ENERGY_RATING, e.POTENTIAL_ENERGY_RATING, e.CURRENT_ENERGY_EFFICIENCY, e.POTENTIAL_ENERGY_EFFICIENCY,
e.PROPERTY_TYPE
FROM property p
LEFT JOIN epc e ON p.postcode = e.POSTCODE AND CONCAT(p.paon, ', ', p.street) = e.ADDRESS1
WHERE p.paon = 8 AND p.postcode = "TS6 9LN"
ORDER BY e.INSPECTION_DATE, p.lastTransferDate DESC
LIMIT 1
Is it possible to select both tables but if 1 doesn't exist, select the 1 that does?
You need a FULL OUTER JOIN. Unfortunately MySQL does not implement this part of the SQL standard. You can simulate a full outer join with two outer joins, though, but it becomes long, and possibly quite cumbersome and error prone.
For example:
select a.col1, b.col2
from table_a a
LEFT join table_b b on ...
union -- here we union both outer joins
select a.col1, b.col2
from table_a a
RIGHT join table_b b on ...
In the second SELECT the table roles are inverted, since it uses a RIGHT JOIN instead of a LEFT JOIN.

LEFT OUTER JOIN selects just one row

I am trying to SELECT data from my database with the method LEFT OUTER JOIN but when I run my syntax the result is just one row. I am sure the result must be more rows.
I also tried the method FULL OUTER JOIN instead of LEFT OUTER JOIN. But when I do that I get an syntax error.
Does someone know why I am gettin just one row?
Here is my sql syntax:
SELECT
cus.cus_id
, cus.name_cus
, cus.address, count(invoice.id) as id2
, CONCAT('€ ', ROUND(SUM(invoice.total),2)) as total
, cus.id
FROM cus
LEFT OUTER JOIN invoice
ON cus.cus_id = invoice.cus_id
You are using aggregate functions without GROUP BY clause:
SELECT
cus.cus_id
, cus.name_cus
, cus.address
, count(invoice.id) as id2
, CONCAT('€ ', ROUND(SUM(invoice.total),2)) as total
, cus.id
FROM cus
LEFT OUTER JOIN invoice ON cus.cus_id = invoice.cus_id
GROUP BY cus.cus_id, cus.name_cus, cus.address, cus.id
Although you need to group only by the unique ID (i.e. cus.id) you should add other fields that are not aggregated to GROUP BY clause as well, even though they do not create additional groups.

How to access parent column from a subquery within a join

I'm trying to left join the second table useri_ban based on the users' ids, with the extra condition: useri_ban.start_ban = max_start.
In order for me to calculate max_start, I have to run the following subquery:
(SELECT MAX(ub.start_ban) AS max_start, user_id FROM useri_ban ub WHERE ub.user_id = useri.id)
Furthermore, in order to add max_start to every row, I need to inner join this subquery's result into the main result. However, it seems that once I apply that join, the subquery is no longer able to access useri.id.
What am I doing wrong?
SELECT
useri.id as id,
useri.email as email,
useri_ban.warning_type_id as warning_type_id,
useri_ban.type as type,
useri.created_at AS created_at
FROM `useri`
inner join
(SELECT MAX(ub.start_ban) AS max_start, user_id FROM useri_ban ub WHERE ub.user_id = useri.id) `temp`
on `useri`.`id` = `temp`.`user_id`
left join `useri_ban` on `useri_ban`.`user_id` = `useri`.`id` and `useri_ban`.`start_ban` = `max_start`
Does this solve your problem? You need GROUP BY in the inner query instead of another join.
SELECT useri.id, useri.email, maxQuery.maxStartBan
FROM useri
INNER JOIN
(
SELECT useri_ban.user_id ubid, MAX(useri_ban.startban) maxStartBan
FROM useri_ban
GROUP BY useri_ban.user_id
) AS maxQuery
ON maxQuery.ubid = useri.id;

LEFT OUTER JOIN AND WHERE on joining table

To elaborate, I'm selecting fields from item and locations tables. Connection is location_id from items table and id field from locations table. After join I'm doing WHERE statement on city_text field from locations table.
Is this legal action since I'm doing WHERE on field from second table?
SELECT uc_items.* ,
uc_users_store.id AS store_id,
uc_users_store.store_name,
uc_users_store.address,
uc_users_store.work_hours,
uc_locations.city_text AS city,
uc_locations.zipcode_text AS zipcode,
uc_locations.state_text AS STATE,
uc_locations.country_text AS country
FROM uc_items
LEFT OUTER JOIN uc_users_store ON uc_items.store_id=uc_users_store.id
LEFT OUTER JOIN uc_locations ON uc_users_store.store_location_id=uc_locations.id
WHERE uc_locations.city_text LIKE "%'.$city.'%"
AND uc_items.iname LIKE "%'.$description.'%"
AND uc_items.expiration_stamp > '.time().'
ORDER BY uc_items.posting_stamp DESC,
uc_items.discount DESC
It's legal, but might lead to unexpected results if the tested value is NULL. However, you could catch these situations by including an IS NULL check.
For instance
WHERE (col = 'value' OR col IS NULL)
Completely legal. However it would be a lot more logical to use INNER JOIN instead of LEFT JOIN since your WHERE statement is concerning the table you are joining to. A pseudo example:
SELECT t1.something, t2.somethin FROM first_table t1 INNER JOIN second_table t2 ON t1.some_id = t2.some_id_from_t1 WHERE t2.some_column='something'

MySQL: why does GROUP_CONCAT lose rows in my multiple join query?

I'm trying to fetch all the rows from table_m which also have an index in table_mi and I'm expecting to get 2 rows as a result (with m.id=3 and m.id=9) - but if I add GROUP_CONCAT to my select then I only get one row returned. Am I having a misshap somewhere within those joins of mine?
Query:
SELECT
m.id,
m.name,
m.keyword,
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
FROM
table_m AS m
INNER JOIN
table_mi as mi ON m.id=mi.m_id
LEFT JOIN
table_ri as ri ON m.id=ri.m_id
LEFT JOIN
table_r AS r ON ri.r_id=r.id
WHERE
(
m.id>0
AND m.active=1
AND mi.p_id=0
AND (mi.pa_id="11" OR (mi.pa_id=0 AND mi.id!=0))
AND mi.u_id=IF((SELECT id FROM table_mi WHERE p_id=0 AND pa_id="11" AND u_id="2")>0,"2",0)
) OR mi.id=0
ORDER BY
mi.priority;
This is what I'm getting as a result:
ID NAME KEYWORD RESTRICTIONS
9 test_a key_a r_key_2,r_key_3,r_key_4
This is what I'm expecting:
ID NAME KEYWORD RESTRICTIONS
9 test_a key_a r_key_2,r_key_3,r_key_4
3 test_b key_b TEST
Please see my full example with schema on sql fiddle: http://sqlfiddle.com/#!2/359d9/1
GROUP_CONCAT is an aggregate function. It will bring back a single row UNLESS you specify a GROUP BY clause (with any fields that are not in the GROUP BY being aggregate fields)
Before the ORDER BY add the following:-
GROUP BY m.id, m.name, m.keyword
That said it looks like you might want to use CONCAT to join 2 values together rather than GROUP_CONCAT
As an aside, your SQL might be easier to read if you eliminate the subselect. Assuming it is bringing back a single record then possibly as follows
SELECT
m.id,
m.name,
m.keyword,
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
FROM
table_m AS m
INNER JOIN
table_mi as mi ON m.id=mi.m_id
LEFT JOIN
table_ri as ri ON m.id=ri.m_id
LEFT JOIN
table_r AS r ON ri.r_id=r.id
LEFT OUTER JOIN
table_mi AS mi2 ON mi2.p_id=0 AND mi2.pa_id="11" AND mi2.u_id="2"
WHERE
(
m.id>0
AND m.active=1
AND mi.p_id=0
AND (mi.pa_id="11" OR (mi.pa_id=0 AND mi.id!=0))
AND mi.u_id=IF(mi2.id >0,"2",0)
) OR mi.id=0
ORDER BY
mi.priority;
You do no need GROUP_CONCAT to achieve what you want.
Instead of :
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
use
IFNULL(r.keyword,'TEST') AS restrictions
OR:
Keep the query as it is and add GROUP BY m.id before ORDER BY