объединение одной таблицы несколько раз в другие таблицы - PullRequest
5 голосов
/ 10 июня 2009

У меня есть три таблицы:

Пользователь таблицы (имя пользователя и имя пользователя)

Ключ таблицы (идентификатор пользователя)

Настольный ноутбук (userid laptopid)

Я хочу, чтобы все пользователи имели либо ключ, либо ноутбук, либо оба. Как мне написать запрос, чтобы он использовал соединение между таблицей User и таблицей Key, а также соединение между таблицей User и таблицей Laptop?

Основная проблема заключается в том, что в реальном сценарии существует около 12 соединений таблиц, например:

"выбрать .. из левого соединения b на (...), c присоединиться к d на (..), e, f, g где ...",

и я вижу, что a может быть присоединен к b, а a также может быть присоединен к f. Итак, если я не могу сделать так, чтобы таблицы a, b и f выглядели бок о бок, как мне написать sql-запрос?

Ответы [ 6 ]

9 голосов
/ 10 июня 2009

Вы можете использовать несколько объединений для объединения нескольких таблиц:

select *
from user u
left join key k on u.userid = k.userid
left join laptop l on l.userid = u.userid

«Левое соединение» также находит пользователей, у которых нет ключа или ноутбука. Если вы замените оба слова на «внутреннее соединение», будут найдены только пользователи с ноутбуком и ключом.

Когда "левое соединение" не находит строку, оно возвращает NULL в своих полях. Таким образом, вы можете выбрать всех пользователей, у которых есть ноутбук или ключ, подобный этому:

select *
from user u
left join key k on u.userid = k.userid
left join laptop l on l.userid = u.userid
where k.userid is not null or l.userid is not null

NULL является особенным, поскольку вы сравниваете его как «поле не является нулевым» вместо «field <> null».

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

select *
from user u
left join laptop l on l.userid = u.userid
left join mouse m on m.laptopid = l.laptopid

Если это не отвечает на ваш вопрос, вы должны уточнить его еще.

2 голосов
/ 10 июня 2009
-- // Assuming that a user can have at max 1 items of each type
SELECT      u.*
-- // Assuming that a user can have more then 1 items of each type, just add DISTINCT:
-- // SELECT      DISTINCT u.*
FROM        "User" u
LEFT JOIN   "Key"    u1 ON u.UserID = u1.UserID
LEFT JOIN   "Laptop" u2 ON u.UserID = u2.UserID
LEFT JOIN   "Server" u3 ON u.UserID = u3.UserID
-- // ...
WHERE       COALESCE(u1.UserID, u2.UserID, u3.UserID /*,...*/) IS NOT NULL
1 голос
/ 10 июня 2009

Решение первое:

SELECT * FROM [User] u
INNER JOIN [Key] k
ON u.userid = k.userid

UNION

SELECT * FROM [User] u
INNER JOIN Laptop l
ON u.userid = l.userid

[...]

Решение второе:

SELECT * FROM [User] u
LEFT JOIN [Key] k
ON u.userid = k.userid
LEFT JOIN Laptop l
ON u.userid = l.userid
LEFT JOIN [...]
WHERE k.userid IS NOT NULL
OR l.userid IS NOT NULL
OR [...]

Просто предположение, также вы можете проверить план выполнения для этих двух, чтобы увидеть, тяжелее ли UNION один или наоборот.

1 голос
/ 10 июня 2009

Как вы описали случай, вы только хотели узнать, есть ли у кого-то ноутбук или ключ. Я бы написал запрос с подзапросом, а не с соединением:

select * 
from user 
where userid in (select userid from key union select userid from laptop)

Причина этого заключается в том, что при объединении человек с несколькими ноутбуками или несколькими ключами будет указан несколько раз (если вы не используете distinct). И даже если вы используете distinct, вы получите менее эффективный запрос (по крайней мере, в Oracle оптимизатор запросов не сможет создать эффективный план).

[Отредактировано, чтобы исправить то, что указал Рашми Пандит.]

1 голос
/ 10 июня 2009
select distinct u.userid, u.username
from User u 
    left outer join Key     /* k on u.userid = k.userid */
    left outer join Laptop  /* l on u.userid = l.userid */
where k.userid is not null or l.userid is not null

EDIT "Основная проблема заключается в том, что в реальном сценарии существует около 12 соединений таблиц, например: "выбрать .. из левого соединения b на (...), c присоединиться к d на (..), e, f, g где ...", и я вижу, что a может быть присоединен к b, и a также может быть присоединен к f. Итак, если я не могу сделать так, чтобы таблицы a, b и f выглядели рядом, как мне написать SQL-запрос? "

Вы можете иметь столько левых внешних соединений, сколько требуется. Присоедините таблицу с первичным ключом к остальным таблицам или к любому другому полю, где значения полей одной таблицы должны совпадать со значениями полей другой таблицы.

например, объяснит лучше, чем слова

select * 
from a
 left outer join b on a.pk = b.fk -- a pk should match b fk
 left outer join c on a.pk = c.fk -- a pk should match c fk
 left outer join d on c.pk = d.fk -- c pk should match d fk

и т. Д.

0 голосов
/ 10 июня 2009
 SELECT * 
 FROM User
 LEFT JOIN Key ON User.id = Key.user_id
 LEFT JOIN Laptop ON User.id = Laptop.user_id
 WHERE Key.id IS NOT NULL OR Laptop.id IS NOT NULL
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...