MySQL проблема соответствия нескольких интересов - PullRequest
3 голосов
/ 06 мая 2011

У меня есть база данных, где пользователи вводят свои интересы. Я хочу найти людей с совпадающими интересами.

Структура таблицы процентов

interestid | username | hobby | location | level | matchinginterestids

Давайте возьмем двух пользователей, чтобы все было просто.

  • Пользователь Джо может иметь 10 записей о различных процентах
  • Пользователь greg может иметь 10 записей о различных процентах.

Я хочу сделать следующий алгоритм

  • Возьмите учетную запись интересов Джо 1 и найдите подходящие места и увлечения в базе данных интересов. Поместите любые совпадающие идентификаторы интересов в поле совпадений. Затем перейдите к записи интереса Джо 2 и т. Д.

Полагаю, мне нужен какой-то цикл for, который будет проходить по всем интересам Джо, а затем будет обновлять каждый раз, когда найдет совпадение в базе данных по интересам. Это возможно даже в MySQL?


Дальнейший пример:

Я Дан. У меня есть 3 интереса. Каждый интерес состоит из 3 предметов:

  • Дэн кошки, питание, волосы
  • Дэн суперленс, днк, микроскопы
  • Дэн фильм, замедленное движение, боевые сцены

У других людей могут быть другие интересы

Джо

  • Джо Коты, питание, сила
  • Джо суперленс, днк, микроскопы

Мо

  • Мое mysql, запросы, php
  • Мо пленка, specialfx, камеры
  • Мо суперлинс, днк, микроскопы

Теперь я хочу, чтобы запрос возвращал следующее при входе в систему как Dan:

Вот ваши совпадения по интересам:

--- интересует кошек для питания волос
Джо интересуется кошками и питанием
Джо и Мо интересуются суперлинзами, днк, микроскопами
Мо интересуется фильмом

Запрос должен пройти через все интересы Дэна и сравнить 3,2,1 тематических совпадений.

Я мог бы сделать это в php из цикла, но он будет постоянно вызывать базу данных, чтобы получить результаты. Мне было интересно, есть ли хитрый способ сделать это, используя один запрос или, может быть, 3 отдельных запроса, один ищет 3 совпадения, один для 2 и один для 1.

Ответы [ 2 ]

5 голосов
/ 06 мая 2011

Это определенно возможно с MySQL, но я думаю, что вы можете пойти по этому поводу неловко.Я бы начал с структурирования таблиц следующим образом:

TABLE Users ( userId, username, location )
TABLE Interests( interestId, hobby )
TABLE UserInterests( userId, interestId, level )

Когда пользователь добавляет интерес, если он еще не был добавлен, вы добавляете его в таблицу Interests, а затем добавляете его втаблица UserInterests.Если вы хотите проверить других близлежащих людей со схожими интересами, вы можете просто запросить таблицу UserInterests для других людей, имеющих сходные интересы, которые уже имеют всю эту информацию для вас:

SELECT DISTINCT userId
  FROM UserInterests
  WHERE interestId IN (
     SELECT interestId
       FROM UserInterests
       WHERE userId = $JoesID
     )

Это можетвозможно, это будет сделано более элегантно без подзапросов, но сейчас я об этом думаю.

4 голосов
/ 09 мая 2011

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

Объясненная схема

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)

Но это плохая, действительно очень плохая идея , потому что:

  1. Thisтолько 3 пользователя на одного пользователя разрешены
  2. Это пустая трата пространства, если у многих пользователей есть 2, 1 или нет интересов
  3. И самое главное, это затрудняет написание запросов.

Пример запроса для связи с таблицей 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

Почему это лучше?

  1. Неограниченное количество интересов на пользователя и наоборот
  2. Нет места впустую, если у пользователя скучная жизнь и мало, если есть какие-либо интересы
  3. Запросы проще обслуживать

Делать его интересным

Просто перечислять всех пользователей не очень весело, потому что тогда нам все равно придется обрабатывать данные в 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, у которых есть хобби, которое соответствует Мо

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...