SQL - несколько условий LEFT JOIN - приоритет

У меня есть 2 таблицы со структурой, похожей на эту:

таблица: пользователь

поля: id, active_office_address_id (может быть 0)

таблица: user_address

поля: id, user_id, тип (дом, офис)

Пользователь может иметь «домашний» адрес (не обязательно) и несколько «офисных» адресов. У меня есть соединение, чтобы получить адрес пользователя, но я хочу, чтобы у пользователя был «домашний» адрес, чтобы получить этот адрес, а не адрес «офиса».

Итак, как я могу получить «домашний» адрес, если он существует, и только если он не существует, чтобы получить «офисный» адрес. (На самом деле запрос намного сложнее и соединение выполняется на 4-5 таблицах)

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

person morandi3    schedule 03.12.2013    source источник
comment
Функция объединения поможет вам, если mysql ее поддерживает.   -  person Dan Bracuk    schedule 03.12.2013
comment
@моранди3 . . . Вам нужны все адреса офисов или только один?   -  person Gordon Linoff    schedule 03.12.2013


Ответы (3)


Вы можете использовать COALESCE() и присоединиться к таблице адресов дважды:

  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
person Hart CO    schedule 03.12.2013
comment
Может быть нужен office.id? Не совсем понятно, но важным битом является COALESCE() и двойное объединение, так как данные адреса предположительно нормализованы. - person Hart CO; 03.12.2013
comment
Что такое домашний.адрес и рабочий.адрес? Идентификатор? - person morandi3; 03.12.2013
comment
Это будет фактическое поле адреса, которое вы пытаетесь вернуть. - person Hart CO; 03.12.2013

Два левых соединения и оператор case дадут вам идентификатор адреса, который вы хотите.

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)

Вы можете вернуть это как дополнительный выбор для конкретного пользователя:

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 = ?)

Это предполагает, что для каждого пользователя существует только один домашний адрес.

person Tom McClure    schedule 03.12.2013
comment
Да, для каждого пользователя существует только один домашний адрес. - person morandi3; 03.12.2013

По крайней мере, в SQL Server, не уверенном в MySql, вы можете использовать оператор case в предложении order by, например:

order by user.id, case user_address.type when 'home' then 1 else 2 end, --additional ordering clauses here
person beercodebeer    schedule 03.12.2013