Spencer Mark
Spencer Mark

Reputation: 5311

MySQL return record where left joined table has no record

I'm having a database with two tables: users, users_addresses and countries.

When I'm selecting user record and binding it to the model I'm using the following statement:

SELECT 
`u`.`id`, `u`.`first_name`, `u`.`last_name`,

`a`.`address_1`, `a`.`address_2`,
`a`.`town`, `a`.`region`, `a`.`post_code`, `a`.`country`,

`c`.`name` AS `country_name`,
`c`.`eu` AS `eu_member`

FROM `users` `u`

LEFT JOIN `users_addresses` `a`
  ON `a`.`user` = `u`.`id`  

LEFT JOIN `countries` `c`
  ON `c`.`id` = `a`.`country`  

WHERE `a`.`default` = 1
AND `u`.`id` = 3

The problem I'm having is that if table users_addresses does not contain corresponding record for the user then I get an empty result. If there is a record - it should only return one marked as default = 1, but obviously it would be better to ensure that it always returns just one in case, for any reason one user will have more than one addresses marked as default.

So my question is - how could I make sure that even if there is no corresponding record in the users_addresses table I will still get at least user record and how to ensure that query will always match just one address record.

Any help would be very much appreciated.

Upvotes: 0

Views: 86

Answers (3)

Gorkk
Gorkk

Reputation: 1056

LEFT JOIN will include entries from the left table if there's no corresponding entry in the right tables.

However in your case you then filter by a.default = 1 which remove entries with no default address.

To avoid that, you will need to either join with a subquery

LEFT JOIN (
  SELECT * FROM user_adresses
  WHERE `default` = 1
) a
ON a.user = u.id

With this option you can limit to at most one 'default' address per user by using a GROUP BY user in the subselect.

Or you could use the a.default = 1 as a join condition and not a where condition, i.e.

LEFT JOIN user_addresses a
  ON a.user = u.id and a.default = 1

Not 100% sure about that last suggestion, but I'm pretty confident this would work.

Edit: and you obviously also have the option suggested by @steinmas, i.e. extending the filter on default to accept also null values.

To ensure you get at most one default address by user, you'll most likely need a GROUP BY user command at some point

Upvotes: 2

i100
i100

Reputation: 4666

This is by definition

The LEFT JOIN keyword returns all rows from the left table (table1), with the matching rows in the right table (table2). The result is NULL in the right side when there is no match.

If you can reorganize the query

Upvotes: 0

steinmas
steinmas

Reputation: 398

Try changing your WHERE clause to this:

WHERE (`a`.`default` = 1 OR `a`.`default` IS NULL)
AND `u`.`id` = 3

Upvotes: 1

Related Questions