joining tables in mysql while one of them is not reachable - mysql

I wrote a query that join 3 tables :
SELECT `notification`.`nid`, `notification`.`type`, `notification`.`read`, `notification`.`time`, `user`.`pro_img`, `user`.`fname` ,`user`.`lname`, `user`.`username`, `accommodation`.`aid`, `accommodation`.`title`, `accommodation`.`home_img`
FROM `notification` RIGHT OUTER JOIN `user` ON `notification`.`rid`=`user`.`id` RIGHT OUTER JOIN `accommodation` ON `notification`.`acco_id`=`accommodation`.`aid`
WHERE `notification`.`uid`=$uid ORDER BY `notification`.`time` DESC;
i want to have result while notification.acco_id= accommodation.aid is not found so empty columns is ok but i want rows

Your query is combining a few things that don't go along. The right joins you are using will preserve anything that's in the right side tables, in your case user and accomodation, but using two of them with the same left side will make this useless. You also have a condition in your where involving the left side of the joins, and this also will make the right joins pointless.
Assuming you want all the notifications, regardless of them being matched with users and accomodations or not, you only need to change from right to left joins.
SELECT notification.nid,
notification.type,
notification.read,
notification.time,
user.pro_img,
user.fname,
user.lname,
user.username,
accommodation.aid,
accommodation.title,
accommodation.home_img
FROM notification
LEFT OUTER JOIN
user
ON notification.rid = user.id
LEFT OUTER JOIN
accommodation
ON notification.acco_id = accommodation.aid
WHERE notification.uid = $uid
ORDER BY notification.time DESC
This will preserve all the rows in notification, and will match them with null values when there are no matching rows on the other table(s).

Related

How can I populate a table when inner join values might be null?

I'm populating a table which is fetching the ids from 2 other tables to display their information, for example, delivery has a Hamburguer and the box, but the user might register the delivery with out the box, only with the hamburguer.
When I make a INNER JOIN SELECT to get the data from the DB it will return 0 results since there is no box and I'm trying to compare the ids that don't exist. It doesn't populate the table then.
SELECT
entrega_telemovel.*,
telemovel.id_telemovel,
telemovel.nroserie,
nro_telemovel.numero_telemovel,
nro_telemovel.id_nrotelemovel,
funcionarios.id_funcionario,
funcionarios.nome
FROM entrega_telemovel
INNER JOIN telemovel
ON entrega_telemovel.telemovel = telemovel.id_telemovel
INNER JOIN nro_telemovel
ON nro_telemovel.id_nrotelemovel = entrega_telemovel.numero_telemovel
INNER JOIN funcionarios
ON funcionarios.id_funcionario = entrega_telemovel.funcionario_entrega
ORDER BY funcionarios.nome;
In this query above entrega_telemovel.telemovel=telemovel.id_telemovel the value in entrega_telemovel.telemovel is null like the example I gave above. So 0 results are returned from the query.
How can I solve this ?
You are looking for a LEFT JOIN.
INNER JOIN only combines rows, that exist in both tables. A LEFT JOIN on the other hand always produces at least one row. If on table does not have a match for it, all columns are set to NULL.
SELECT
entrega_telemovel.*,
telemovel.id_telemovel,
telemovel.nroserie,
nro_telemovel.numero_telemovel,
nro_telemovel.id_nrotelemovel,
funcionarios.id_funcionario,
funcionarios.nome
FROM entrega_telemovel
LEFT JOIN telemovel
ON entrega_telemovel.telemovel = telemovel.id_telemovel
LEFT JOIN nro_telemovel
ON nro_telemovel.id_nrotelemovel = entrega_telemovel.numero_telemovel
LEFT JOIN funcionarios
ON funcionarios.id_funcionario = entrega_telemovel.funcionario_entrega
ORDER BY funcionarios.nome;
You want to show all entrega_telemovel entries, no matter whether they have a match in entrega_telemovel or not. This is what an outer join does.
SELECT ...
FROM entrega_telemovel et
LEFT OUTER JOIN telemovel t ON et.telemovel = t.id_telemovel
...

MySQL - How to get one of the repeated records given a condition in SQL?

I have the next results from a query. I did this:
Where the user "Adriana Smith" with ID 6 is repeated because she has different contract dates, to do that I did a left join from table bo_users to bo_users_contracts (1:m One to Many Relation). The query is below:
SELECT bo_users.ID, bo_users.display_name, COALESCE (bo_users_contracts.contract_start_date,'-') AS contract_start_date, COALESCE (bo_users_contracts.contract_end_date, '-') AS contract_end_date, COALESCE (bo_users_contracts.current,'-') AS current
FROM bo_users
LEFT JOIN bo_users_contracts ON bo_users.ID = bo_users_contracts.bo_users_id
LEFT JOIN bo_usermeta ON bo_users.ID = bo_usermeta.user_id
WHERE (bo_usermeta.meta_key = 'role' AND bo_usermeta.meta_value = 'member')
But I want to get all users, but from user Adriana I just want to get the occurrence where "current" column = 1.
So the final result would be the 3 user's records:
Alejandro, Rhonda and Adriana (with "current" = 1)
Thank you!
Since you want to limit on a table being outer joined, the limit should be placed on the join itself so the all records from bo_users is retained. (as indicated desired by the outer join)
Essentially the limit is applied before the join so the unmatched records from BO_users to bo_users_contracts are kept. If applied after the join in a where clause the records from BO_user without a matching record would have a null value for current and thus be excluded when the current=1 filter is applied.
In this example the only values which should be in the where would be from table BO_USERS.
I'd even move the bo_usermeta filters to the join or you may lose bo_users; or the left join on the 3rd table should be an inner join.
SELECT bo_users.ID
, bo_users.display_name
, COALESCE (bo_users_contracts.contract_start_date,'-') AS contract_start_date
, COALESCE (bo_users_contracts.contract_end_date, '-') AS contract_end_date
, COALESCE (bo_users_contracts.current,'-') AS current
FROM bo_users
LEFT JOIN bo_users_contracts
ON bo_users.ID = bo_users_contracts.bo_users_id
and bo_users_contracts.current = 1
LEFT JOIN bo_usermeta --This is suspect
ON bo_users.ID = bo_usermeta.user_id
WHERE (bo_usermeta.meta_key = 'role' --this is suspect
AND bo_usermeta.meta_value = 'member') --this is suspect
The lines reading this is suspect are that way because you have a left join which means you want all users from bo_users.. However if a user doesn't have a meta_key or meta_value defined, they would be eliminated. Either change the join to an inner join or move the where clause limits to the join. I indicate this as you're query is "inconsistent" in it's definition leading to ambiguity when later maintained.

How to get value from tables using LEFT JOIN?

This is my structure of tables:
tables_structure
and there's tbl_owner, tbl_rooms and tbl_class.
How do I get id_class and class name from tbl_class.
The original source code is like this:
SELECT
clas.id_class,
clas.class_name
FROM
tbl_rooms AS room
LEFT JOIN tbl_class AS clas ON room.id_class = clas.id_class
LEFT JOIN tbl_owner AS own ON room.id_owner = own.id_owner
WHERE own.id_owner='1';
However, it did not work. Please help me?
SELECT
clas.id_class,
clas.class_name
FROM
tbl_rooms AS room
LEFT JOIN tbl_class AS clas ON room.id_class = clas.id_class
LEFT JOIN tbl_owner AS own ON room.id_owner = own.id_owner
WHERE own.id_owner='1';
Left Joins and wheres can be a little confusing.
Here you are asking for all rooms and if they have a class return it, it they have an owner return it. Which is done by the left join.
Then after getting that info, Your asking to filter the results by owner = 1
Given that there were left joins used to build this data, you have now said only show the results where both joins matched. Effectively turning the left join to an inner join.
I would take away the where clause and check the join conditions are producing results you expect first, then start to allow the where to narrow the result set.
The correct way to check if a left join is a condition is (own.id_owner='1') OR (own.id_owner is null)
That will bring back all owner = 1 and all unknown owners

Select from two tables gives Not unique table/alias

I have 3 tables (user, user_authority_rules_history & authority_rules_history) I want to select values from two of the tables if they match my criterias.
My query looks like this
SELECT
user_authority_rules_history.download_date,
authority_rules_history.*
FROM
user_authority_rules_history,
authority_rules_history
LEFT JOIN
user_authority_rules_history
ON
user_authority_rules_history.authority_rule_id = authority_rules_history.id
LEFT JOIN
user
ON
user_authority_rules_history.user_id = user.id
WHERE
user.id = 1
Im able make it work, if i leave out user_authority_rules_history.download_date from my query, but then im obviously missing that data. What am i doing wrong here ?
You have an extra table reference to user_authority_rules_history in the from clause. A simple rule: never use commas in the from clause.
I think this is what you intend:
SELECT user_authority_rules_history.download_date,
authority_rules_history.*
FROM authority_rules_history LEFT JOIN
user_authority_rules_history
ON user_authority_rules_history.authority_rule_id = authority_rules_history.id LEFT JOIN
user
ON user_authority_rules_history.user_id = user.id
WHERE user.id = 1
Note that you are filtering on user.id = 1. This is undoing your left join, so you might as well use inner join on the tables. I am not sure what you really intend, but this should fix your problem.

mysql right join not working as expected

When I use right join I get the same results as using left join or just join. Can anyone show me where I have gone wrong?
I have 3 tables as follows:
langugages
id
code eg "hu","en"
language_default
id
text
language_translations
id
lang_id (FK the id of the language in the languages table)
default_lang_id (FK the id of the text in the languages_default table)
text (the translation)
When I execute the following query, I expect to get all of the hungarian translations from the language_translations table and all of the text fields from the language_default table with a null value where there is no hungarian translation.
SELECT `language_translations`.`text`
, `language_default`.`text`
FROM `languages`
, `language_translations`
RIGHT JOIN `language_default` ON `language_default`.`id` = `language_translations`.`default_lang_id`
WHERE `languages`.`code` = 'hu'
AND `languages`.`id` = `language_translations`.`lang_id`
Instead I only get text from the language_default table where there are translations for that text in the tranlsation table. I would expect that behaviour from a left join or normal join but not a right join. Any ideas why I am not getting all of the entries from the langugage_defailt table?
First of all you are using combination of normal join and rights join in wrong way. You can use as per below query.
2nd thing right join means you will get all record from right side and corresponding records from left side and if left side does not have corresponding record then it will show NULL.
Left join is its reverse.
Normal join or comma join will provide only common rows.
So if your tables only have common rows then all joins will provide same results.
SELECT
`language_translations`.`text` , `language_default`.`text`
FROM `languages` AS l
JOIN `language_translations` AS t
ON l.`id` = t.`lang_id` AND l.`code` = 'hu'
RIGHT JOIN `language_default` AS d
ON d.`id` = t.`default_lang_id`;
Don't mix implicit joins and explicit joins. A simple rule is: don't use , in the from clause. The following restructures your query to use left outer join:
SELECT `language_translations`.`text`, ld.`text`
FROM language_default ld left outer join
language_translations lt
on ld.`id` = lt.`default_lang_id` left outer join
`languages` l
on l.`id` = lt.`lang_id` and l.`code` = 'hu' ;
When using outer joins, you need to be very careful about where additional conditions go. Conditions on the driving table (the first a left outer join, the last for a right outer join) can go in the where clause. For other tables, the conditions should go in the on clause. Otherwise, they turn the outer join into an inner for the simple reason that (almost) any comparison to NULL is equivalent to false.