Конференция "Базы" » как избавиться от 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]
    Ничего не понимаю, а где временная таблица?
  • stas © (12.10.16 19:14) [20]
    kate158, прочитайте внимательно stas ©   (11.10.16 15:19) [5]
  • iop © (12.10.16 19:21) [21]
    стасик, зачем ей читать твоё пять,
    если тебе русским языком написали,
    что дерево кривое, и рекурсивный запрос на ихней иерархии зацикливается.

    вот тем и не устраивает.
  • stas © (13.10.16 08:57) [22]
    iop ©   (12.10.16 19:21) [21]
    Тоже верно. Точнее stas ©   (11.10.16 15:22) [6].
    Можно конечно в цикле поставить максимальный уровень вложенности, допустим 100.
    Но это закопать проблему еще глубже.

    iop ©   (12.10.16 17:49) [18]
    Есть еще вариант:
    id=1, parentId=3
    id=2, parentId=1
    id = 3 parentId=2
  • kate158 © (13.10.16 11:14) [23]

    > iop ©   (12.10.16 19:21) [21]

    чем дерево кривое? на хабре полно статей про такую структуру дерева, где parent_id=id
    id=1 parent_id=пусто
    id=2 parent_id=1
    id=3 parent_id=1
    id=4 parent_id=2
    id=5 parent_id=2
    сейчас ничего не зацикливается, но в случае логической ошибки может. так сказали наши программисты. я с этим не сталкивалась, не знаю. но мой запрос завернули :)
  • stas © (13.10.16 11:27) [24]
    kate158 ©   (13.10.16 11:14) [23]
    А не проще сделать check на логическую ошибку при записи?
  • iop © (13.10.16 11:28) [25]
    чем дерево кривое? на хабре полно статей про такую структуру дерева, где parent_id=id

    корнет, вы женщина?
  • stas © (13.10.16 11:31) [26]
    kate158 ©
    Вы наверное все таки напишите запрос, чтобы понять как работает рекурсивное дерево.
  • kate158 © (13.10.16 11:36) [27]
    iop ©   (13.10.16 11:28) [25] я в этом не виновата :)
  • kate158 © (14.10.16 16:07) [28]

    > stas ©   (13.10.16 11:31) [26]

    stas ©   (13.10.16 11:31) [26]
    with t as(
    SELECT id, parent_id, name
    FROM accounts.groups b WHERE id='7e8a97b0-7353-11e6-84f9-2314e71f8a19'
    union all
     select  a.id, a.parent_id, a.name
    from accounts.groups as a
    inner join b on b.parent_id = a.id)
    select * from t



    ?
  • stas © (14.10.16 21:28) [29]
    kate158 ©   (14.10.16 16:07) [28]
    Имел ввиду, доделайте тот,что начали ).
 
Конференция "Базы" » как избавиться от with recursive [postgresql]
Есть новые Нет новых   [134427   +34][b:0][p:0.002]