Деревья в SQL.

поддеревьев Следующий запрос будет брать уволенного служащего как параметр и удалять поддерево, расположенное под ним/ней. Уловка в этом запросе - то, что Вы используете ключ, но Вы должны заставить работать левые и правые значения. Ответ - набор скалярных подзапросов:

   DELETE FROM Personnel
    WHERE lft BETWEEN
    (SELECT lft FROM Personnel WHERE emp = :downsized)
    AND
    (SELECT rgt FROM Personnel WHERE emp = :downsized);

Проблема состоит в том, что после этого запроса появляются промежутки в последовательности номеров множеств. Это не мешает выполнять большинство запросов к дереву, т.к. свойство вложения сохранено. Это означает, что Вы можете использовать предикат BETWEEN в ваших запросах, но другие операции, которые зависят от плотности номеров, не будут работать в дереве с промежутками. Например, Вы не сможете находить листья, используя предикат (right-left=1), и не сможете найти число узлов в поддереве, используя значения left и right его корня.
К сожалению, Вы потеряли информацию, которая будет очень полезна в закрытии тех промежутков - а именно правильные и левые номера корня поддерева. Поэтому, забудьте запрос, и напишите вместо этого процедуру:

   CREATE PROCEDURE DropTree (downsized IN CHAR(10) NOT NULL)

    BEGIN ATOMIC

    DECLARE dropemp CHAR(10) NOT NULL;

    DECLARE droplft INTEGER NOT NULL;

    DECLARE droprgt INTEGER NOT NULL;

    --Теперь сохраним данные поддерева:

    SELECT emp, lft, rgt

    INTO dropemp, droplft, droprgt

    FROM Personnel

    WHERE emp = downsized;

    --Удаление, это просто...

    DELETE FROM Personnel

    WHERE lft BETWEEN droplft and droprgt;

    --Теперь уплотняем промежутки:

   

    UPDATE Personnel

    SET lft = CASE

    WHEN lft > droplf

    THEN lft - (droprgt - droplft + 1)

    ELSE lft END,

    rgt = CASE

    WHEN rgt > droplft

    THEN rgt - (droprgt - droplft + 1)

    ELSE rgt END;END;


Реальная процедура должна иметь обработку ошибок, но я оставляю это как упражнение для читателя.
Удалениеузла
Удаление одиночного узла в середине дерева тяжелее чем удаление полных поддеревьев. Когда Вы удаляете узел в середине дерева, Вы должны решить, как заполнить отверстие. Имеются два пути. Первый метод к повышает одного из детей к позиции первоначального узла (предположим, что отец умирает, и самый старший сын занимает бизнес, как показано на рисунке 2). Самый старший потомок всегда показывается как крайний левый дочерний узел под родителем. Однако с этой этой операцией имеется проблема. Если старший ребенок имеет собственнх детей, Вы должны решить, как обработать их, и так далее вниз по дереву, пока Вы не добираетесь к листу.
Второй метод для удаления одиночного узла в середине дерева состоит в том, чтобы подключить потомков к предку первоначального узла (можно сказать, что мамочка умирает, и дети приняты бабушкой), как показано на рисунке 3. Это получается автоматически во модели вложенных множеств, Вы просто удаляете узел, и его дети уже содержатся в узлах его предка. Однако, Вы должны быть осторожны, при закрытии промежутка, оставленного стиранием. Имеется различие в изменении нумерации потомков удаленного узла и изменения нумерации узлов справа. Ниже - процедура выполняющая это:

   CREATE PROCEDURE DropNode (downsized IN CHAR(10) NOT NULL)

    BEGIN ATOMIC

    DECLARE dropemp CHAR(10) NOT NULL;

    DECLARE droplft INTEGER NOT NULL;

    DECLARE droprgt INTEGER NOT NULL;

    --Теперь сохраним данные поддерева:

    SELECT emp, lft, rgt

    INTO dropemp, droplft, droprgt

    FROM Personnel

    WHERE emp = downsized;

   

    --Удаление, это просто...

    DELETE FROM Personnel

    WHERE emp = downsized;

    --Теперь уплотняем промежутки:

   

    UPDATE Personnel

    SET lft = CASE

    WHEN lft BETWEEN droplft AND droprgt THEN lft - 1

    WHEN lft > droprgt THEN lft - 2

    ELSE lft END

    rgt = CASE

    WHEN rgt BETWEEN droplft AND droprgt THEN rgt - 1

    WHEN rgt > droprgt THEN rgt -2

    ELSE rgt END;

    WHERE lft > droplft;

    END;

Листинг 1

   CREATE TABLE Personnel

    (emp    CHAR(10)        PRIMARY KEY,

    salary    DECIMAL(8,2)    NOT NULL CHECK(salary > = 0.00),

    lft    INTEGER        NOT NULL,

    rgt    INTEGER        NOT NULL,

    CHECK(lft < rgt));

   

    INSERT INTO Personnel VALUES ('Albert', 1000.00, 1, 28);

    INSERT INTO Personnel VALUES ('Bert', 900.00, 2, 5);

    INSERT INTO Personnel VALUES ('Charles', 900.00, 6, 19);

    INSERT INTO Personnel VALUES ('Diane', 900.00, 20, 27);

    INSERT INTO Personnel VALUES ('Edward', 750.00, 3, 4);

    INSERT INTO Personnel VALUES ('Fred', 800.00, 7, 16);

    INSERT INTO Personnel VALUES ('George', 750.00, 17, 18);

    INSERT INTO Personnel VALUES ('Heidi', 800.00, 21, 26);

    INSERT INTO Personnel VALUES ('Igor', 500.00, 8, 9);

    INSERT INTO Personnel VALUES ('Jim', 100.00, 10, 15);

    INSERT INTO Personnel VALUES ('Kathy', 100.00, 22, 23);

    INSERT INTO Personnel VALUES ('Larry', 100.00, 24, 25);

    INSERT INTO Personnel VALUES ('Mary', 100.00, 11, 12);

    INSERT INTO Personnel VALUES ('Ned', 100.00, 13, 14);


Удаление одиночного узла в середине дерева тяжелее чем удаление полных поддеревьев. Когда Вы удаляете узел в середине дерева, Вы должны решить, как заполнить отверстие. Имеются два пути. Первый метод к повышает одного из детей к позиции первоначального узла (предположим, что отец умирает, и самый старший сын занимает бизнес. Самый старший потомок всегда показывается как крайний левый дочерний узел под родителем.Второй метод для удаления одиночного узла в середине дерева состоит в том, чтобы подключить потомков к предку первоначального узла (можно сказать, что мамочка умирает, и дети приняты бабушкой).
© Joe CelkoDBMS Online - April 1996Translated by SDM
Деревья в SQL. Часть 3.
Давайте продолжим наше обсуждение модели вложенных множеств для деревьев в SQL. Я не собираюсь рассматривать любую из моих предидущих статей и буду предполагать, что Вы все еще имеете копию таблицы Personnel, которую я использовал для примеров (DBMS, март 1996, страница 24). Если Вы не имеете прошлых выпусков, Вы можете осчастливить моего издателя, приобретя их.
Меня спрашивают, почему я не показываю больше процедурного кода в примерах. Прямо сейчас, ANSI и ISO пробуют договориться о стандартном процедурном языке для триггеров и хранимых процедур называемом SQL/PSM. Однако, этот стандарт еще не утвержден, что означает, что я должен использовать или свой собственный псевдо-код или выбирать одного производителя. Я решил использовать пока Английские комментарии, но я буду начинать использовать SQL/PSM, когда он будет завершен.
Наиболее хитрая часть обработки деревьев в SQL это нахождение способа конвертировать модель матрицы смежности в модель вложенных множеств в пределах структуры чистого SQL. Было бы довольно просто загрузить таблицу матрицы смежности в программу, и затем использовать рекурсивную программу преобразование дерева из учебника колледжа, чтобы построить модель вложенных множеств.
Честно говоря, такое преобразованиме дерева могло бы быть быстрее чем то, что я собираюсь показать Вам. Но я хочу сделать это в чистом SQL, чтобы доказать следующее: Вы можете делать на декларативном языке то же, что Вы можете делать на процедурном языке. Поскольку это обучающее упражнение, я буду объяснять с болезненной детальностью.
Классический подход к решению проблемы состоит в том, чтобы брать самое простой случай проблемы, и смотреть, можете ли Вы применять его к более сложным случаям. Если дерево не имеет узлов, то преобразование просто - ничего не делать. Если дерево имеет один узел, то преобразование простое - устанавливают левое значение в 1 и правое значение в 2. Природа матрицы смежности такова, что Вы можете двигаться только по одному уровню одновременно, так что давайте посмотрим на дерево с двумя уровнями - корень и непосредственные потомки. Таблица модели смежности напоминала бы следующее:

   CREATE TABLE Personnel

    (emp CHAR(10) NOT NULL PRIMARY KEY,

    boss CHAR(10));

    Personnel

    emp    boss

    =================

    'Albert'    NULL

    'Bert'    'Albert'

    'Charles'    'Albert'

    'Diane'    'Albert'

Давайте поместим модель вложенных множеств в ее собственную рабочую таблицу:

   CREATE TABLE WorkingTree(

    emp CHAR (10),

    boss CHAR(10),

    lft INTEGER NOT NULL DEFAULT 0,

    rgt INTEGER NOT NULL DEFAULT 0);

Из предидущих абзацев этой статьи, Вы знаете, что корень дерева имеет левое значение 1, и что правое значение является удвоенным числом узлов в дереве. Пусть в рабочей таблице столбец boss будет всегда содержать ключевое значение корня первоначального дерева. В действительности, это будет имя вложенного множества:

   INSERT INTO WorkingTree

    --convert the root node

    SELECT P0.boss, P0.boss, 1,

    2 * (SELECT COUNT(*) + 1

        FROM Personnel AS P1

        WHERE P0.boss = P1.boss)

        FROM Personnel AS P0;

Теперь, Вы должны добавить потомков в таблицу вложенных множеств. Первоначальный босс останется тот же самый. Порядок потомков - естественный порядок ключа; в данном случае emp char(10):

   INSERT INTO WorkingTree

    --convert the children

    SELECT DISTINCT P0.emp, P0.boss,

    2 * (SELECT COUNT(DISTINCT emp)

    FROM Personnel AS P1

    WHERE P1.emp < P0.emp

    AND P0.boss IN (P1.emp, P1.boss)),

    2 * (SELECT COUNT(DISTINCT emp)

    FROM Personnel AS P1

    WHERE P1.emp < P0.emp

    AND P0.boss IN (P1.boss, P1.emp)) + 1

    FROM Personnel AS P0;


Фактически, Вы можете использовать эту процедуру, чтобы конвертировать модель матрицы смежности в лес деревьев, каждое из которых - модель вложенных множеств, идентифицированная ее корневым значением. Таким образом, генеалогическое дерево Альберта - набор строк, которые имеют Альберта как предка, генеалогическое дерево Берта - набор строк, которые имеют Берта как предка, и так далее. (Эта концепция иллюстрирована в рисунках 1 и 2.
Поскольку первоначальная таблица матрицы смежности повторяет нелистовые узлы, некорневые узлы, в столбцах emp и boss, таблица WorkingTree дублирует узлы как корень в одном дереве и как потомок в другом. Запрос также будет странно себя вести со значением NULL в столбце boss первоначальной таблицы матрицы смежности, так что Вы будете должны очистить таблицу WorkingTree следующим запросом:

   DELETE FROM WorkingTree

    WHERE boss IS NULL OR emp IS NULL;

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...