В соответствии со специальным запросом от Даниеля, хотя это своего рода дубликат, но неважно.
Объясненная схема
TABLE User (id, username, location )
TABLE Interests(id, hobby )
TABLE UserInterest(userId, interestId, level )
Таблица users
имеет только пользователяданные и поле первичного ключа в начале: id
.
Поле первичного ключа является чистым полем связи, остальные поля являются информационными полями.
Таблица Interest
снова имеет первичный ключ, которыйиспользуется для связи с некоторым информационным полем
(ну, ну, просто один, но это потому, что это пример)
Обратите внимание, что users
и interests
не связаныкаким-либо образом.
Странно, с чем это связано?
Ну, есть проблема ... Один user
может иметь несколько intrests
, а intrests
может принадлежать несколькимpeople
.Мы можем решить эту проблему, изменив таблицу пользователей следующим образом:
TABLE users (id, username, location, intrest1, intrest2, intrest3)
Но это плохая, действительно очень плохая идея , потому что:
- Thisтолько 3 пользователя на одного пользователя разрешены
- Это пустая трата пространства, если у многих пользователей есть 2, 1 или нет интересов
- И самое главное, это затрудняет написание запросов.
Пример запроса для связи с таблицей bad users
SELECT * FROM user
INNER JOIN interests ON (user.intrest1 = interests.id) or
(user.intrest2 = interests.id) or
(user.intrest3 = interests.id);
И это только для простого запроса со списком всех пользователей и их интересов.
Он быстро становится ужаснымсложный, как вещи прогрессируют.
отношения «многие ко многим»
Решение проблемы отношения «многие ко многим» заключается в использовании таблицы ссылок.
Это уменьшает множествоотношение «многие-многие» в два отношения «один ко многим».
A: 1 userinterest
ко многим user
*
B: 1 userinterest
ко многим interests
Пример запроса с использованием таблицы ссылок
SELECT * FROM user
INNER JOIN userInterest ON (user.id = userInterest.userID) //many-to-1
INNER JOIN interest ON (interest.id = userInterest.InterestID); //many-to-1
Почему это лучше?
- Неограниченное количество интересов на пользователя и наоборот
- Нет места впустую, если у пользователя скучная жизнь и мало, если есть какие-либо интересы
- Запросы проще обслуживать
Делать его интересным
Просто перечислять всех пользователей не очень весело, потому что тогда нам все равно придется обрабатывать данные в php или как-то еще.Но в конце концов нет необходимости делать так, чтобы SQL был языком запросов, поэтому давайте зададим вопрос:
Дайте всем пользователям, которые разделяют интерес, с пользователем Moe.
Хорошо, давайте составим кулинарную книгу и соберем наши ингредиенты.Что нам нужно.
Ну, у нас есть user
"Мо", и у нас есть другие user
, все, кроме не"Мо".
И у нас естьразделяемые между ними интересы.
И нам также понадобится таблица ссылок userInterest
, потому что именно так мы связываем user
и interests
.
Давайте сначала перечислим все хобби Мо
SELECT i_Moe.hobby FROM interests AS i_Moe
INNER JOIN userInterests as ui2 ON (ui2.InterestID = i_Moe.id)
INNER JOIN user AS u_Moe ON (u_Moe.id = ui2.UserID)
WHERE u_Moe.username = 'Moe';
Теперь мы объединяем выбор для всех пользователей только с хобби Мо.
SELECT u_Others.username FROM interests AS i_Others
INNER JOIN userinterests AS ui1 ON (ui1.interestID = i_Others.id)
INNER JOIN user AS u_Others ON (ui1.user_id = u_Others.id)
/*up to this point this query is a list of all interests of all users*/
INNER JOIN Interests AS i_Moe ON (i_Moe.Hobby = i_Others.hobby)
/*Here we link Moe's hobbies to other people's hobbies*/
INNER JOIN userInterests as ui2 ON (ui2.InterestID = i_Moe.id)
INNER JOIN user AS u_Moe ON (u_Moe.id = ui2.UserID)
/*And using the link table we link Moe's hobbies to Moe*/
WHERE u_Moe.username = 'Moe'
/*We limited user-u_moe to only 'Moe'*/
AND u_Others.username <> 'Moe';
/*and the rest to everybody except 'Moe'*/
Поскольку мы используем INNER JOIN
в полях ссылок, будут рассматриваться только совпадения, а неспички будут выброшены.Если вы читаете запрос по-английски, он выглядит следующим образом.
Рассмотрите всех пользователей, которые не Moe
, назовите их U_others
.
Рассмотрите пользователя Moe
, назовите его U_Moe.
Считайте хобби пользователя Moe
, называйте их i_Moe
Считайте хобби других пользователей, называйте их i_Others
Теперь свяжите i_Others
хобби с u_Moe
хобби
Вернуть только пользователей из U_Others
, у которых есть хобби, которое соответствует Мо
Надеюсь, это поможет.