Рекурсивный CTE, включая объединения внутри якоря и рекурсивное выражение - PullRequest
0 голосов
/ 29 июня 2018

Итак, у меня есть три таблицы со следующей схемой,

Users(id, name)

Colleagues(id1, id2)

Friends(id1, id2)

И мне нужно написать запрос, который возвращает каждую пару идентификаторов, чтобы можно было связаться с id_2 с id_1, используя произвольное количество соединений между коллегами и друзьями. Я разработал запрос, который дает мне каждое соединение, используя либо коллег, либо друзей, но не оба. Вот что я придумал, пытаясь использовать обе таблицы в одном CTE:

WITH RECURSIVE Reachable (id_1, id_2)
AS (
SELECT
    *
FROM (
    SELECT
        id,
        FRIENDS.id2
    FROM
        USERS,
        FRIENDS
    WHERE
        FRIENDS.id1 = USERS.id
    UNION
    SELECT
        id,
        COLLEAGUES.id2
    FROM
        USERS,
        COLLEAGUES
    WHERE
        COLLEAGUES.id1 = USERS.id)
UNION
SELECT
    *
FROM (
    SELECT
        REACHABLE.id_1,
        FRIENDS.id2
    FROM
        REACHABLE,
        FRIENDS
    WHERE
        REACHABLE.id_2 = FRIENDS.id1
    UNION
    SELECT
        REACHABLE.id_1,
        COLLEAGUES.id2
    FROM
        REACHABLE,
        COLLEAGUES
    WHERE
        REACHABLE.id_2 = COLLEAGUES.id1));

Но я получаю эту ошибку:

Error: near line 1: recursive reference in a subquery: Reachable

Значит ли это, что я не могу / не должен использовать подзапросы в рекурсивном вызове вообще? Можно ли выполнить этот запрос внутри того же CTE? если так, как я могу это сделать? Заранее спасибо!

1 Ответ

0 голосов
/ 29 июня 2018

Ссылка на рекурсивный CTE не должна быть в подзапросе, и две части, разделенные UNION (ALL), должны быть верхним уровнем WITH.

Если нет различий между друзьями и коллегами по этому запросу, просто объедините две таблицы перед выполнением рекурсивного CTE:

WITH RECURSIVE
Connections AS (
  SELECT id_1, id_2 FROM Colleagues
  UNION ALL 
  SELECT id_1, id_2 FROM Friends
),
Reachable(id_1, id_2) AS (
  SELECT ...
  FROM Users, Connections
  ...
  UNION
  ...
)
SELECT * FROM Reachable;
...