Конференция "Базы" » как избавиться от with recursive [postgresql]
 
  • kate158 © (11.10.16 12:41) [0]
    как избавиться от with recursive в запросе:

    BEGIN
    RETURN query
    WITH RECURSIVE R AS
    (SELECT id
    FROM accounts.groups WHERE id=(_id)
    UNION ALL
      SELECT accounts.groups.id
      FROM accounts.groups
         JOIN R
             ON accounts.groups.parent_id = r.id
    )
    SELECT *FROM R;
    END;

  • stas © (11.10.16 13:48) [1]
    Уточните пожалуйста, вы хотите тот же результат, не используя WITH RECURSIVE ?
  • kate158 © (11.10.16 14:56) [2]
    именно так.
  • stas © (11.10.16 15:10) [3]
    быстрее без введения дополнительных полей никак.
    А вот если поле добавить текстовое и заполнять его таким образом:
    1. родитель
    1.1. - 1 потомок 1 уровня
    1.2.  - 2 потомок 1 уровня
    1.1.1.  - 1 потомок 2 уровня

    То получить список потомков по родителю

    select * from table where hierarchy like '1.%'



    Ну, а дальше на сколько фантазии хватит.
  • kate158 © (11.10.16 15:12) [4]
    изменение структуры таблицы не планировалось . иерархия у нас организована с помощью полей id, parent_id. можно ли организовать функцию с выводом дерева с помощью цикла?
  • stas © (11.10.16 15:19) [5]
    да. А чем with recursive не устраивает?
    У вас будет входящий Id родителя чтобы получить потомков или нужно все дерево?
  • stas © (11.10.16 15:22) [6]
    Если все дерево, то
    1. Перед циклом наполняете  временную таблицу temp записями из своей table
    2. В цикле объединяете вновь добавленные записи таблицы temp со своей таблицей и результат вставляете опять в temp и так пока объединяется.
  • stas © (11.10.16 15:30) [7]
    Если входящий Id, то в п.1. наполняем не всеми записями, а только отобранной по id
  • iop © (11.10.16 15:40) [8]
    можно ли организовать функцию с выводом дерева с помощью цикла?

    тебе какая разница где будет рекурсия, в постгрессе или в цикле?

    это к тому, что придумав иерархическую организацию данных,
    надо юзать рекурсию по полной,
    а не спрашивать как от нее избавиться.
  • kate158 © (11.10.16 18:42) [9]
    как будет выглядеть подобный запрос в цикле?
  • iop © (11.10.16 19:34) [10]
    он будет выглядеть как корова обутая в седло
  • kate158 © (12.10.16 10:11) [11]
    мне нужна корова :) почему этот вариант возвращает только вершину дерева?
    CREATE OR REPLACE FUNCTION accounts.without_recursive(_id uuid)  RETURNS table (id uuid, parent_id uuid, name character varying(64))AS
    $BODY$
    DECLARE
    r uuid;
    BEGIN
    --return query
    FOR r in SELECT id, parent_id, name FROM accounts.groups WHERE id = _id
    LOOP
     return query
       select ag.id, ag.parent_id, ag.name from accounts.groups as ag join r ON ag.id = r.parent_id;
       RETURN NEXT;
    END LOOP;
    RETURN;
    END;
    $BODY$
    LANGUAGE 'plpgsql' STABLE STRICT

  • iop © (12.10.16 10:21) [12]
    ну iop,
    раскоментарь первый ретурн.
    пропала и сама вершина?

    и какой вывод?
  • kate158 © (12.10.16 10:58) [13]
    хорошо, я поняла. тема названа не верно. нужно было написать не 'как избавиться от рекурсии' а как можно по-другому запросить данные.

    > iop

    а вот что не так с ретурнами я не догоняю.
  • iop © (12.10.16 11:02) [14]
    если после раскоментаренного первого ретурна пропадает вершина иерархии, то это значит, что когда он закоментарен, то ты вылетаешь из цикла по ретурну на первой же итерации. и в выборке только вершина дерева.
  • stas © (12.10.16 13:23) [15]
    Че-то я не понял, в чем проблема с with recursive ?
    К сожалению синтаксиса postgresql я не знаю.
    Но по ходу 1 что увидел, Вам нужно объединять вновь добавленные записи а не все. т.е. на 1 итерации все, допустим от 1...100, на второй уже от 101 до 120.
  • kate158 © (12.10.16 17:14) [16]
    если в базе сделать логическую ошибку, то используя в запросе with recursive можно повесить базу.
    этот код выбирает родителя и первую ветку детей, остальное не выводит. почему???
    CREATE OR REPLACE FUNCTION accounts.without_recursive(_id uuid)  RETURNS table (id uuid, parent_id uuid, name character varying(64))AS
    $BODY$
    DECLARE
    row_ record;
    BEGIN
    RETURN query
    --возвращаем первую ветку дерева
    SELECT us.id, us.parent_id, us.name FROM accounts.groups us WHERE us.id = _id;
    --возвращаем детей
    FOR row_ IN SELECT us.id, us.parent_id, us.name FROM accounts.groups us WHERE us.id = _id
    LOOP
    RETURN query
    SELECT r.id, r.parent_id, r.name FROM accounts.groups AS r WHERE r.parent_id =row_.id;
      RETURN NEXT;
    END LOOP;
    RETURN;
    END;
    $BODY$
    LANGUAGE plpgsql VOLATILE

  • iop © (12.10.16 17:21) [17]
    короче.
    без рекурсии у тебя ничего не получится.
    даже если однажды из этой функции вылезет вторая ветка детей.
    но так как рекурсией можно повесить вашу кривую иерархию,

    то вывод простой

    спиливать дерево и клепать плоские таблицы заточенные на N поколений вложенности.
    не больше.
  • iop © (12.10.16 17:49) [18]
    хотя если дерево на id + parent_id
    то как его можно зациклить?

    простой вариант когда id = parent_id

    других вроде нет, а этот вычищается на раз.
  • stas © (12.10.16 19:12) [19]
    kate158 ©   (12.10.16 17:14) [16]
    Ничего не понимаю, а где временная таблица?
 
Конференция "Базы" » как избавиться от with recursive [postgresql]
Есть новые Нет новых   [134427   +34][b:0][p:0.002]