Рекурсивные записи SQL: как я могу свернуть до «только одного уровня»? - PullRequest
3 голосов
/ 04 января 2012

У меня есть записи с идентификатором проекта и «идентификатором наследования», то есть проектом, от которого унаследован текущий проект.Уровень наследования неизвестен.

Теперь мне нужно свернуть это следующим образом: «наследовать от самого верхнего» * ​​1003 *

Например:

1006 <- 1005 <- 1002 <- 999

prj_id / inherit_id

999  / 1002

1002 / 1005

1005 / 1006

должно свернуться до

1006 <- 1005 

1006 <- 1002

1006 <- 999

prj_id / inherit_id

999  / 1006

1002 / 1006

1005 / 1006

Можно ли это сделать в операторе SQL без циклов?Создание временных таблиц в порядке.Это должно работать для FireBird, SQL Server, Oracle 9+ (то есть 3 набора операторов в порядке)

Я только получил это далеко:

Записи, которые наследуются от записи, которая сама наследуется снова:

select tt_prj_id,tt_name,tt_inherit_id from tt_prj a

where a.tt_inherit_id in

(select tt_prj_id from tt_prj b

 where b.tt_inherit_id is not null

 and b.tt_inherit_id > 0)

Кто может мне помочь дальше?

Ответы [ 3 ]

6 голосов
/ 04 января 2012

Что-то вроде следующего должно помочь вам начать (это не окончательное решение!):

with recursive project_tree as (
   select tt_prj_id, cast(tt_prj_id as varchar(500))||'/' as id_path, tt_prj_id as root_id
   from tt_prj
   where tt_inherit_id = 0

   union all

   select c.tt_prj_id, id_path || cast(c.tt_prj_id as varchar(100)) ||'/', null
   from tt_prj c
     join project_tree p on c.tt_inherit_id = p.tt_prj_id
)
select *
from project_tree;

Это работает Firebird 2.5 (может также работать с 2.1, но у меня нет под рукой одного правасейчас)

Он должен работать с SQL Server, когда вы удаляете ключевое слово recursive (что требуется стандартом ANSI, но с тех пор, когда Microsoft об этом позаботилась ...), и вам нужно заменить стандартобъединение строк || с оператором +.

Oracle поддерживает только рекурсивные CTE до 11.2.В предыдущей версии вам нужно переписать это, используя CONNECT BY, что будет примерно так:

select tt_prj_id, tt_inherit_id, sys_connect_by_path(tt_prj_id, '/')
from tt_prj
start with tt_inherit_id = 0
connect by prior tt_prj_id = tt_inherit_id;
1 голос
/ 04 января 2012

Пользователь a_horse_with_no_name правильный.Эта операция может быть выполнена с рекурсивными CTE.Проверьте эту ссылку для получения дополнительной информации.

http://blog.sqlauthority.com/2008/07/28/sql-server-simple-example-of-recursive-cte/

Еще раз, Пинал Дэйв ftw.

1 голос
/ 04 января 2012

Выполните поиск по transitive closure tables или nested sets. Их структура позволяет эффективно запрашивать реляционные данные, но требует больше обслуживания для вставок / обновлений / удалений, а таблицы закрытия потребуют хранения дополнительных записей (компромиссное пространство для эффективности).

...