Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL - LEFT JOIN multiple conditions - priority

I have 2 tables with a structure similar with this:

table: user

fields: id, active_office_address_id (this can be 0)

table: user_address

fields: id, user_id, type (home, office)

A user can have a "home" address (not mandatory) and multiple "office" addresses. I have a join to get a user address, but I want that if the user have a "home" address to get that address, not "office" address.

So, how can I get "home" address if exists, and only if that not exists to get "office" address. (In reality the query is much more complicated and the join is done on 4-5 tables)

SELECT * FROM user LEFT JOIN user_address ON (user.id = address.user_id AND 
(user_address.type = "home" OR user.active_office_address_id = user_address.id))
group by user.id
like image 822
morandi3 Avatar asked Dec 03 '13 17:12

morandi3


People also ask

Does the order of multiple Left joins matter?

It doesn't matter.

Does the order of the on condition of a left join matter?

The order doesn't matter for INNER joins but the order matters for (LEFT, RIGHT or FULL) OUTER joins. Outer joins are not commutative.

Is Left join or WHERE faster?

The LEFT JOIN query is slower than the INNER JOIN query because it's doing more work.

Is WHERE clause faster than join?

“Is there a performance difference between putting the JOIN conditions in the ON clause or the WHERE clause in MySQL?” No, there's no difference. The following queries are algebraically equivalent inside MySQL and will have the same execution plan.


2 Answers

You can use COALESCE() and join to your address table twice:

  SELECT user.id
       ,COALESCE(home.address, office.address) AS Address
  FROM user 
  LEFT JOIN user_address AS home
     ON user.id = home.user_id 
       AND home.type = "home"
  LEFT JOIN user_address AS office
     ON user.active_office_address_id = office.user_id 
  GROUP BY user.id
like image 195
Hart CO Avatar answered Sep 25 '22 08:09

Hart CO


Two left joins and a case statement will give you the address id you want.

SELECT user.*,CASE WHEN home_addr.id IS NOT NULL THEN home_addr.id ELSE ofc_addr.id END AS addr_id
FROM user
LEFT JOIN user_address AS home_addr
  ON (user.id = home_addr.user_id AND home_addr.type = 'home')
LEFT JOIN user_address AS ofc_addr
  ON (user.active_office_address_id = ofc_addr.id)

You could feed this back in as a sub-select for a particular user:

SELECT * FROM user LEFT JOIN user_address
WHERE user.id = ?
AND user_address.user_id = user.id
AND user_address.id IN
    (SELECT CASE WHEN home_addr.id IS NOT NULL THEN home_addr.id ELSE ofc_addr.id END AS addr_id
    FROM user
    LEFT JOIN user_address AS home_addr
      ON (user.id = home_addr.user_id AND home_addr.type = 'home')
    LEFT JOIN user_address AS ofc_addr
      ON (user.active_office_address_id = ofc_addr.id)
    WHERE user.id = ?)

This assumes that only one home address exists per user.

like image 21
Tom McClure Avatar answered Sep 25 '22 08:09

Tom McClure