КАК СОЗДАТЬ РЕКУРСИВНУЮ ФУНКЦИЮ В POSTGREQL 9.6? - PullRequest
0 голосов
/ 05 марта 2020

У меня есть таблица menus и таблица menu_headings. Они выглядят так:

menus таблица:

id | object_id | name         | menu_heading_id | price | parent_id |

3  | 45        | Chicken soup | 4               | 120   |     0     |
4  | 45        | Whiskey      | 5               | 65    |     0     |
5  | 45        | Jack Daniels | 5               | 100   |     4     |

menu_headings таблица:

id | object_id | name      |
4  | 45        | Hot meals |
5  | 45        | Drinks    |

Я новичок в postgresql и хочу написать рекурсивную функцию в моем запросе pg sql. Я хочу получить данные примерно так:

-Hot meals
    +Chicken soup*

-Drinks
   -Whiskey
     -Jack Daniels

Просьба помочь мне получить это

1 Ответ

0 голосов
/ 07 марта 2020

Вы можете получить необходимые данные из одного запроса с помощью рекурсивного CTE. Хитрость в том, чтобы удерживать нисходящие уровни вместе. В качестве функции этот запрос становится единым элементом в функции SQL. Что касается форматирования, которое вам нужно, то это то, что лучше оставить приложению (в общем, это всегда лучше для форматирования.) Я бы, вероятно, даже не пытался сделать это в SQL и не буду делать этого здесь. Вы можете попробовать это как упражнение. Но чтобы помочь в этом, я сгенерировал 2 дополнительных столбца. Первый столбец (new_heading) либо нулевой, либо содержит звездочку (*). Звездочка указывает, что эта строка представляет строку заголовка. Последний столбец (hier_level) показывает уровень в иерархии для этой строки (обратите внимание, что заголовок будет иметь уровень 0) и может использоваться для определения требуемого отступа.

create or replace function todays_menu()
  returns table (new_heading   text
                ,menu_heading  text
                ,menu_item     text
                ,price         numeric
                ,hier_level    integer
                )
language sql
as $$
   with recursive the_menu (menu_heading, menu_item, price,  item_id, heading_id, parent_id, mpath) as
        (select mh.name, m.name menu_item, m.price, m.id item_id, m.menu_heading_id, m.parent_id, array[m.id]  
           from menu m 
           join menu_headings mh on m.menu_heading_id = mh.id   
          where parent_id is null 
         union all
         select mh.name, m.name, m.price, m.id ,m.menu_heading_id, m.parent_id, array_append(tm.mpath, m.id)   
           from the_menu tm
           join menu m on  m.parent_id = tm.item_id
           join menu_headings mh on m.menu_heading_id = mh.id     
        )        
   select case when coalesce(lag(menu_heading) over( order by heading_id, mpath),'') <> menu_heading then '*' else null end  new_menu
        , menu_heading, menu_item, price, array_length(mpath,1) hier_level
     from  the_menu
    order by heading_id, mpath;
$$;    

-- test
select * from todays_menu();

В функции обратите внимание на столбец mpath. Этот столбец создает массив идентификаторов меню. Поскольку массивы могут быть отсортированы, это используется для поддержания каждой цепи в дереве в правильном отношении друг к другу. Также он определяет упомянутый выше уровень hier_level. Примечание. Сам запрос можно извлечь и запустить отдельно. Кроме того, это зависит от следующего предложения @a_horse_with_no_name, чтобы использовать null без parent_id вместо 0. Это всегда должно соблюдаться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...