SQL Oracle, как записать sql оператор, который проверяет если пользователь в моей сети (т.е. друзья или друг друзей)

У меня есть эта проблема. Данный a users таблица, которая состоит из имени пользователя пользователей в социальной сети и friends таблица, которые содержат имя пользователя и friendname пользователя как ниже...

username friendname

John        Thomas
Chris       James

... Я пытаюсь записать SQL-оператор, который будет, если пользователь будет в моей сети. Другими словами, тот пользователь является другом или другом друзей?

Я танцевал вокруг этой проблемы и мог только придумать этот запрос:

SELECT f2.username, f2.friendname 
FROM friends f2 
WHERE f2.username IN (
      SELECT f1.friendname 
      FROM friends f1 
      WHERE f1.username = 'Thomas') 
AND f2.friendname <> 'user1' 
AND f2.friendname = 'user2';    

Это в основном проверяет, если пользователь, если друг моего друга т.е. просто возвращает пустой указатель если ложь.

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

8
задан APC 19 February 2010 в 16:05
поделиться

2 ответа

SELECT  *
FROM    (
        SELECT  username
        FROM    friends
        START WITH
                username = 'myname'
        CONNECT BY
                friendname = PRIOR username
                AND level <= 3
        )
WHERE   username = 'friendname'
        AND rownum = 1

Обновляйте уровень по мере необходимости: вы можете искать друзей третьего уровня и т.д.

Если отношения дружбы симметричны, вам следует сделать следующий запрос:

WITH    q AS
        (
        SELECT  username, friendname
        FROM    friends
        UNION ALL
        SELECT  friendname, username
        FROM    friends
        ),
        f AS
        (
        SELECT  friendname, level
        FROM    q
        START WITH
                username = 'Thomas'
        CONNECT BY NOCYCLE
                username = PRIOR friendname
        )
SELECT  *
FROM    f
WHERE   friendname = 'Jo'
        AND rownum = 1

Этот запрос может быть выполнен намного быстрее, если вы денормализуете свою таблицу: храните две записи для каждой дружбы, например, так:

CREATE TABLE dual_friends (orestes NOT NULL, pylades NOT NULL, CONSTRAINT pk_dualfriends_op PRIMARY KEY (orestes, pylades)) ORGANIZATION INDEX
AS
SELECT  username, friendname
FROM    friends
UNION ALL
SELECT  friendname, username
        FROM    friends

Затем вы можете просто заменить CTE выше на dual_friends:

WITH    f AS
        (
        SELECT  pylades, level
        FROM    dual_friends
        START WITH
                orestes  = 'Thomas'
        CONNECT BY NOCYCLE
                orestes = PRIOR pylades
                AND level <= 3
        )
SELECT  *
FROM    f
WHERE   pylades = 'Jo'
        AND rownum = 1

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

5
ответ дан 5 December 2019 в 22:17
поделиться

Вы можете использовать соединение с помощью

1
ответ дан 5 December 2019 в 22:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: