|
|
|
Решение по перемещению узлов в таблице вложенных множеств
|
|||
|---|---|---|---|
|
#18+
-- Предлагаю решение - хранимую процедуру p_dlj_move для перемещения/переподчинения -- узла+подчинённых ему узлов в таблице вложенных множеств (дереве) -- Структура иерархической таблицы t_dolj: -- id_dolj INT -- ID записи -- lft_dolj INT -- Левая граница множества -- rgt_dolj INT -- Правая граница множества -- klfn_name CHAR(30) -- имя узла -- del_ TINYINT -- 0-запись активна 1-запись помечена на удаление IF EXISTS (SELECT name FROM sysobjects WHERE name = 'p_dlj_move' AND type = 'P') DROP PROCEDURE p_dlj_move GO CREATE PROCEDURE [dbo].[p_dlj_move] @Id_which INT = NULL, -- ID перемещаемого пункта @id_target INT = NULL -- ID пункта назначения (к кому подключение) AS SET NOCOUNT ON IF @Id_which IS NULL BEGIN RAISERROR (' Должно быть обязательно указано ID перемещаемого пункта!',16,1) RETURN END IF @id_target IS NULL BEGIN RAISERROR (' Должно быть обязательно указано ID пункта назначения!',16,1) RETURN END DECLARE @l_List BIT, @d_lft INT, @d_rgt INT, @cnt_Ins INT, @right_most_sibling INT, @transcount INT SET @l_List=0 SET @transcount=@@TRANCOUNT IF @transcount=0 BEGIN TRANSACTION mytran12 ELSE SAVE TRAN mytran12 IF EXISTS -- проверяем не есть ли попытка переместить пункт внутрь самого себя -- (т.е. подчинить себя своим же подчинённым) (SELECT * FROM t_dolj WITH (TABLOCKX HOLDLOCK) -- Полная блокировка таблицы до конца транзакции!!! WHERE id_dolj=@id_target AND id_dolj IN (SELECT p1.id_dolj -- выбираем все подчинённые перемещаемому пункту записи FROM t_dolj AS p1, t_dolj AS p2 WHERE p2.lft_dolj+1<=p1.lft_dolj AND p1.lft_dolj<=p2.rgt_dolj AND p2.id_dolj = @Id_which AND p1.del_=0)) BEGIN ROLLBACK TRAN mytran12 RAISERROR (' Недопустимо перемещать пункт самого в себя !',16,1) RETURN END IF EXISTS -- проверяем: не есть ли бестолковая попытка снова подчинить перемещаемый пункт -- своему же непосредственному "начальнику" (SELECT * FROM t_dolj WHERE id_dolj=@id_target AND id_dolj IN (SELECT MAX(p2.id_dolj) AS id_boss -- выбираем запись-"непосредственного начальника" перемещаемого пункта FROM t_dolj AS p1, t_dolj AS p2 WHERE p2.lft_dolj<p1.lft_dolj AND p1.lft_dolj<p2.rgt_dolj AND p1.id_dolj = @Id_which AND p2.del_=0)) BEGIN ROLLBACK TRAN mytran12 RAISERROR (' Данный пункт уже непосредственно "подчиняется" указанному !',16,1) RETURN END IF EXISTS( -- проверяем: является ли активным листом узел, к которому намечается подключение SELECT * FROM t_dolj WHERE id_dolj=@id_target AND del_=0 AND id_dolj IN -- выбираем все активные листья: (SELECT id_dolj FROM t_dolj WHERE lft_dolj=rgt_dolj-1 AND del_=0)) SET @l_List=1 IF @l_List=1 BEGIN -- Проверки: есть ли в других таблицах ссылки на узел-лист, к которому намечается -- прикрепить в подчинение перемещаемый пункт. Если да, то ОТКАТ! ...... ...... END -- Запоминаем границы перемещаемого пункта: SELECT @d_lft=lft_dolj, @d_rgt=rgt_dolj FROM t_dolj WHERE id_dolj=@Id_which -- Помечаем на удаление перемещаемый пункт и его подчинённые записи UPDATE t_dolj SET del_=2 WHERE lft_dolj BETWEEN @d_lft AND @d_rgt SET @cnt_Ins=@@ROWCOUNT -- эту команду сразу за предыдущей! IF @@ERROR<>0 BEGIN ROLLBACK TRAN mytran12 RAISERROR (' При переносе узла: ошибка пометки на удаление перемещаемого(ых) пункта(ов)!',16,1) RETURN END -- Уплотняем промежутки после "удаления" UPDATE t_dolj SET lft_dolj = CASE WHEN lft_dolj>@d_lft THEN lft_dolj-(@d_rgt-@d_lft+1) ELSE lft_dolj END, rgt_dolj = CASE WHEN rgt_dolj>@d_lft THEN rgt_dolj-(@d_rgt-@d_lft+1) ELSE rgt_dolj END WHERE del_=0 IF @@ERROR<>0 BEGIN ROLLBACK TRAN mytran12 RAISERROR (' При переносе узла: ошибка уплотнения дерева!',16,1) RETURN END -- Выясняем правую границу узла, к которому присоединение, после уплотнения SET @right_most_sibling =(SELECT rgt_dolj FROM t_dolj WHERE id_dolj = @id_target AND del_=0) -- Регенерация дерева с учётом последующего восстановления перемещаемых пунктов UPDATE t_dolj SET lft_dolj = CASE WHEN lft_dolj > @right_most_sibling THEN lft_dolj+@cnt_Ins*2 ELSE lft_dolj END, rgt_dolj = CASE WHEN rgt_dolj >= @right_most_sibling THEN rgt_dolj+@cnt_Ins*2 ELSE rgt_dolj END WHERE rgt_dolj >= @right_most_sibling AND del_=0 IF @@ERROR<>0 BEGIN ROLLBACK TRAN mytran12 RAISERROR (' При переносе узла: ошибка регенерации дерева!',16,1) RETURN END -- "восстанавливаем" перемещаемые пункты, подчиняя новому узлу UPDATE t_dolj SET lft_dolj=@right_most_sibling+lft_dolj-@d_lft, rgt_dolj=@right_most_sibling+@cnt_Ins*2-1-@d_rgt+rgt_dolj, del_=0 WHERE del_=2 IF @@ERROR=0 BEGIN IF @transcount=0 COMMIT TRANSACTION END ELSE BEGIN ROLLBACK TRAN mytran12 RAISERROR (' При переносе узла: ошибка восстановления перемещаемого(ых) пукта(ов) в указанном месте!',16,1) RETURN END ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.05.2002, 06:13:30 |
|
||
|
|

start [/forum/topic.php?fid=46&fpage=3470&tid=1822549]: |
0ms |
get settings: |
4ms |
get forum list: |
8ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
47ms |
get topic data: |
6ms |
get forum data: |
2ms |
get page messages: |
14ms |
get tp. blocked users: |
1ms |
| others: | 202ms |
| total: | 288ms |

| 0 / 0 |
