Запрос, чтобы получить предметы, представляющие интерес для всех пользователей Y, где Y делится> = 3 интересами с пользователем X - PullRequest
0 голосов
/ 11 ноября 2018

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

mysql> select uID, name from User;
+-----+-------------------+
| uID | name              |
+-----+-------------------+
|   1 | Alice             |
|   2 | Bob               |
|   5 | Iron Maiden       |
|   4 | Judas Priest      |
|   6 | Lesser Known Band |
|   3 | Metallica         |
+-----+-------------------+
6 rows in set (0.00 sec)

mysql> select * from Follower;
+-----------+------------+
| subjectID | observerID |
+-----------+------------+
|         3 |          1 |
|         4 |          1 |
|         5 |          1 |
|         6 |          1 |
|         3 |          2 |
|         4 |          2 |
|         5 |          2 |
+-----------+------------+
7 rows in set (0.00 sec)

mysql> call newFollowSuggestionsForName('Bob');
+-------------------+
| name              |
+-------------------+
| Lesser Known Band |
+-------------------+
1 row in set (0.00 sec)

Я хочу сделать операцию, которая предложит пользователю X список пользователей, которым они могут заинтересоваться. Я думал, что одной эвристикой может быть показ X для всех y, за которыми следует пользователь y, где X и y следуют как минимум за 3 из тех же пользователей. Ниже приведен SQL-код, который я придумал для этого. У меня вопрос: можно ли сделать это более эффективно или лучше другими способами?

DELIMITER //
CREATE PROCEDURE newFollowSuggestionsForName(IN in_name CHAR(60))
BEGIN

DECLARE xuid INT;
SET xuid = (select uID from User where name=in_name);  

select name
from User, (select subjectID
            from follower
            where observerID in (
                select observerID
                from Follower
                where observerID<>xuid and subjectID in (select subjectID from Follower where observerID=xuid)
                group by observerID
                having count(*)>=3
            )
    ) as T
where uID = T.subjectID and not exists (select * from Follower where subjectID=T.subjectID and observerID=xuid);

END //
DELIMITER ;

Ответы [ 2 ]

0 голосов
/ 11 ноября 2018

Я думаю, что основной запрос начинается с получения всех «наблюдателей», которые разделяют три «субъекта» с данным наблюдателем:

select f.observerid
from followers f join
     followers f2
     on f.subjectid = f2.subjectid and
        f2.observerid = 2
group by f.observerid
having count(*) = 3;

Остальная часть запроса просто объединяет имена, чтобы соответствовать вашей парадигме использования имен для ссылок, а не идентификаторов.

0 голосов
/ 11 ноября 2018

Рассмотрим следующий рефакторинг кода SQL (без проверки без данных) для использования в хранимой процедуре.

select u.`name`
from `User` u
inner join 
   (select subf.observerID, subf.subjectID
    from follower subf
    where subf.observerID <> xuid
   ) f
on u.UID = f.subjectID 
inner join 
   (select f1.observerID
    from follower f1
    inner join follower f2
      on f1.subjectID = f2.subjectID 
     and f1.observerID <> xuid
     and f2.observerID = xuid
    group by f1.observerID
    having count(*) >= 3
   ) o
on f.observerID = o.observerID 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...