2016-01-25 4 views
2

У меня есть следующие таблицы:ВЫБРАТЬ из нескольких таблиц с использованием составного первичного ключа

Users: 
+--------+------+ 
| UserID | Name | 
+--------+------+ 
|  1 | Bob | 
|  2 | Mike | 
|  3 | Tim | 
|  4 | Joe | 
+--------+------+ 

Friends: 
+---------+---------+ 
| UserID1 | UserID2 | 
+---------+---------+ 
|  1 |  2 | 
|  1 |  3 | 
|  3 |  4 | 
|  4 |  2 | 
+---------+---------+ 

Теперь, скажем, Боб входит в мою службу. Мне нужно запустить запрос, который будет загружать все его UserIDs его друзей, а также их имена.

Bob's friends: 
+--------+------+ 
| UserID | Name | 
+--------+------+ 
|  2 | Mike | 
|  3 | Tim | 
+--------+------+ 

Обратите внимание, что таблица «Друзья» содержит составной первичный ключ с использованием как UserID1, так и UserID2. Каждая «дружба» указана только в таблице один раз.

Что было бы лучшим способом справиться с этим? Другими словами, какой запрос следует использовать для поиска друзей пользователя, состоящего как из их UserID, так и Name? Очевидно, что для выбора данных из нескольких таблиц потребуется какое-то предложение JOIN.

ответ

2

Дружба указана только один раз в таблице. Если данные примера представляют Mike как имеющие трех друзей, тогда нам нужно запросить таблицу friends в обоих направлениях. Я бы использовал два SELECT и объединил результаты с оператором набора UNION ALL. Пример:

SELECT uf.userid 
    , uf.name 
    FROM users uf 
    JOIN friends ff 
    ON ff.userid1 = uf.userid 
    JOIN users sf 
    ON sf.userid = ff.userid2 
WHERE sf.name = 'Mike' 
UNION ALL 
SELECT ut.userid 
    , ut.name 
    FROM users ut 
    JOIN friends ft 
    ON ft.userid2 = ut.userid 
    JOIN users st 
    ON st.userid = ft.userid1 
WHERE st.name = 'Mike' 

Есть другие подходы к запросу, которые возвращают эквивалентный результат.

+0

Это очень продуманный ответ на то, что кажется простым вопросом с быстрым взглядом. Могу ли я со всем уважением предложить изменить «UNION ALL» на «UNION»? Это потому, что никто не заставит нас вставлять '(2, 4)' в таблицу 'friends'. «UNION» устранит удвоенный результат. Смотрите это [скрипка] (http://sqlfiddle.com/#!9/fa1fa/4). Знаете ли вы способ (другой, затем триггер), чтобы предотвратить вставку обратного ключа здесь? – MyBrainHurts

+1

Использование 'UNION' вместо' UNION ALL' приведет к тому, что MySQL выполнит операцию «sort unique» для устранения повторяющихся строк. И это может быть дорогостоящим на больших наборах. Если эта операция не требуется, мы обычно получаем лучшую производительность с помощью «UNION ALL». В вопросе указывалось, что дружба хранится только один раз в таблице. Вы абсолютно правы, что если оба (2,4) и (4,2) сохраняются в таблице, этот запрос будет возвращать «дублированные» результаты. И нет, я не знаю, каким образом база данных может принуждать ограничение к избыточным строкам без триггера. – spencer7593

2

Прежде всего, вы хотите присоединиться, чтобы узнать, кто такие друзья Боба. Затем вам нужно присоединиться, чтобы увидеть имена своих друзей.

SELECT u2.* FROM users u1 
JOIN friends ON friends.userid1 = u1.userid 
JOIN users u2 ON u2.userid = friends.userid2 
WHERE u1.name = 'Bob' 
+0

вместо этого выберите конкретные столбцы, так как это приведет к ненужным столбцам. – Rahul

+0

В общем, да, но в этом случае это не будет – evanv

Смежные вопросы