Един от начините за представяне на йерархични данни в релационни таблици е чрез използване на модела на вложените множества. При модела на вложените множества йерархията се представя с помощта вложени контейнери.
1. МОДЕЛ НА ВЛОЖЕНИТЕ МНОЖЕСТВА (NESTED
SET MODEL)
доц. д-р Цветанка Георгиева-Трифонова
2. МОДЕЛ НА ВЛОЖЕНИТЕ МНОЖЕСТВА (NESTED SET
MODEL) – СЪДЪРЖАНИЕ
Същност
Извличане на цялото дърво
Намиране на всички върхове-листа
Извличане на път до даден елемент
Намиране на дълбочината на върховете
Агрегатни функции във вложени множества
Добавяне на нови върхове
Изтриване на върхове
22Цветанка Георгиева
3. СЪЩНОСТ
Моделът на вложените множества
е един от начините за представяне на йерархични данни
в релационни таблици;
йерархията се представя с помощта вложени контейнери.
33Цветанка Георгиева
4. СЪЩНОСТ (2)
Йерархията се поддържа, като всяка категория съдържа
подкатегориите си.
Представянето на йерархията в таблица се осъществява
чрез използване на левите и десните стойности за записване
на вложените в дадена категория елементи (подкатегории).
44Цветанка Георгиева
5. СЪЩНОСТ (3)
За определяне на левите и десните стойности се започва
номериране от най-лявата страна на най-външния елемент и
се продължава надясно.
55Цветанка Георгиева
7. ИЗВЛИЧАНЕ НА ЦЯЛОТО ДЪРВО
Възможно е извличане на цялото дърво чрез използване на
съединяване на таблицата със себе си, при което се свързва
родителски връх parent с всеки връх node, лявата стойност
на който е между лявата и дясната стойност на неговия
родителски връх.
SELECT node.CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND parent.CategoryName = 'Всички'
ORDER BY node.lft
77Цветанка Георгиева
8. ИЗВЛИЧАНЕ НА ЦЯЛОТО ДЪРВО (2)
SELECT node.CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND parent.CategoryName = 'Всички'
ORDER BY node.lft
88Цветанка Георгиева
9. ИЗВЛИЧАНЕ НА ЦЯЛОТО ДЪРВО (3)
SELECT node.CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND parent.CategoryName = 'Всички'
ORDER BY node.lft
99Цветанка Георгиева
10. НАМИРАНЕ НА ВСИЧКИ ВЪРХОВЕ-ЛИСТА
Може да се забележи, че левите и десните стойности на
листовите върхове са последователни числа.
Затова намирането на листовите върхове се извършва чрез
намиране на върховете, за които rgt = lft + 1.
SELECT CategoryName
FROM nested_categories
WHERE rgt = lft + 1
1010Цветанка Георгиева
11. ИЗВЛИЧАНЕ НА ПЪТ ДО ДАДЕН ЕЛЕМЕНТ
Намирането на върховете, които са предшественици на
даден връх, може да извърши със заявка от следния вид:
SELECT parent.CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.CategoryName = 'Бази от данни'
ORDER BY node.lft
1111Цветанка Георгиева
12. ИЗВЛИЧАНЕ НА ПЪТ ДО ДАДЕН ЕЛЕМЕНТ (2)
SELECT parent.CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.CategoryName = 'Бази от данни'
ORDER BY node.lft
1212Цветанка Георгиева
13. НАМИРАНЕ НА ДЪЛБОЧИНАТА НА ВЪРХОВЕТЕ
За намирането на дълбочината на всеки връх може да се
използва функцията COUNT заедно с GROUP BY, за да се
преброят върховете-предшественици на всеки връх:
SELECT node.CategoryName,
(COUNT(parent.CategoryName) - 1) AS depth
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.CategoryName, node.lft
ORDER BY node.lft
1313Цветанка Георгиева
14. НАМИРАНЕ НА ДЪЛБОЧИНАТА НА ВЪРХОВЕТЕ (2)
SELECT node.CategoryName,
(COUNT(parent.CategoryName) - 1) AS depth
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.CategoryName, node.lft
ORDER BY node.lft
1414Цветанка Георгиева
15. НАМИРАНЕ НА ДЪЛБОЧИНАТА НА ВЪРХОВЕТЕ (3)
Дълбочината на всеки връх може да се използва за
извеждане на върховете в йерархията, така че всеки
елемент да има отстъп, съответстващ на неговата дълбочина.
SELECT REPLICATE(' ',
5* (COUNT(parent.CategoryName) – 1)) +
node.CategoryName
AS CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.CategoryName, node.lft
ORDER BY node.lft
1515Цветанка Георгиева
16. НАМИРАНЕ НА ДЪЛБОЧИНАТА НА ВЪРХОВЕТЕ (4)
SELECT REPLICATE(' ',
5* (COUNT(parent.CategoryName) – 1)) +
node.CategoryName
AS CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft
BETWEEN parent.lft AND parent.rgt
GROUP BY node.CategoryName, node.lft
ORDER BY node.lft
1616Цветанка Георгиева
17. НАМИРАНЕ НА ДЪЛБОЧИНАТА НА ВЪРХОВЕТЕ (5)
Вместо интервали могат да се добавят тагове <li></li>,
както и задаване на атрибута class на тези тагове,
съответстващ на дълбочината на върховете.
SELECT '<li class="level' +
LTRIM(STR(COUNT(parent.CategoryName) - 1)) +
'">' +
node.CategoryName + '</li>'
AS CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.CategoryName, node.lft
ORDER BY node.lft
1717Цветанка Георгиева
18. НАМИРАНЕ НА ДЪЛБОЧИНАТА НА ВЪРХОВЕТЕ (6)
SELECT '<li class="level' +
LTRIM(STR(COUNT(parent.CategoryName) - 1)) +
'">' +
node.CategoryName + '</li>'
AS CategoryName
FROM nested_categories AS node,
nested_categories AS parent
WHERE node.lft
BETWEEN parent.lft AND
parent.rgt
GROUP BY node.CategoryName,
node.lft
ORDER BY node.lft
1818Цветанка Георгиева
19. АГРЕГАТНИ ФУНКЦИИ ВЪВ ВЛОЖЕНИ МНОЖЕСТВА
Нека е добавена таблица за продукти, за да може да се
демонстрира използването на агрегатни функции.
1919Цветанка Георгиева
20. АГРЕГАТНИ ФУНКЦИИ ВЪВ ВЛОЖЕНИ МНОЖЕСТВА (2)
За извеждане на категориите в йерархията и броя на
продуктите от всяка категория може да се използва следната
заявка:
SELECT parent.CategoryName,
COUNT(Products.ProductName) AS CountOfProducts
FROM nested_categories AS node,
nested_categories AS parent,
Products
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.CategoryID = Products.CategoryID
GROUP BY parent.CategoryName
2020Цветанка Георгиева
21. АГРЕГАТНИ ФУНКЦИИ ВЪВ ВЛОЖЕНИ МНОЖЕСТВА (3)
SELECT parent.CategoryName,
COUNT(Products.ProductName) AS CountOfProducts
FROM nested_categories AS node,
nested_categories AS parent,
Products
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.CategoryID = Products.CategoryID
GROUP BY parent.CategoryName
2121Цветанка Георгиева
22. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ
Ако трябва да се добави връх след даден връх (например
Научна литература), е необходимо да се изпълнят
следните действия:
Всички върхове, които се намират надясно от новия връх
трябва да увеличат лявата и дясната си стойност с 2;
предшествениците на новия връх увеличават само
дясната си стойност с 2;
Лявата стойност на новия връх се получава от дясната
стойност на дадения връх, като се увеличи с 1;
Дясната стойност на новия връх се получава от дясната
стойност на дадения връх, като се увеличи с 2.
2222Цветанка Георгиева
23. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ (2)
Ако трябва да се добави връх след даден връх (например
Научна литература), е необходимо да се изпълнят
следните действия:
Всички върхове, които се намират надясно от новия връх
трябва да увеличат лявата и дясната си стойност с 2;
Лявата стойност на новия връх се получава от дясната
стойност на дадения връх, като се увеличи с 1;
Дясната стойност на новия връх се получава от дясната
стойност на дадения връх, като се увеличи с 2.
2323Цветанка Георгиева
24. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ (3)
DECLARE @myRight int
SELECT @myRight = rgt FROM nested_categories
WHERE CategoryName = 'Научна литература'
UPDATE nested_categories SET rgt = rgt + 2
WHERE rgt > @myRight
UPDATE nested_categories SET lft = lft + 2
WHERE lft > @myRight
INSERT INTO nested_categories
(CategoryID, CategoryName, lft, rgt)
VALUES (12, 'Учебници', @myRight + 1, @myRight + 2)
2424Цветанка Георгиева
25. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ (4)
DECLARE @myRight int
SELECT @myRight = rgt FROM nested_categories
WHERE CategoryName = 'Научна литература'
UPDATE nested_categories SET rgt = rgt + 2
WHERE rgt > @myRight
UPDATE nested_categories SET lft = lft + 2
WHERE lft > @myRight
INSERT INTO nested_categories
(CategoryID, CategoryName, lft, rgt)
VALUES (12, 'Учебници', @myRight + 1, @myRight + 2)
2525Цветанка Георгиева
26. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ (5)
Ако трябва да се добави връх като наследник на даден връх,
който няма съществуващи наследници (например Бази от
данни), е необходимо да се изпълнят следните действия:
Всички върхове, които се намират надясно от дадения
връх трябва да увеличат лявата и дясната си стойност с 2,
както и дясната стойност на дадения връх;
предшествениците на новия връх увеличават само
дясната си стойност с 2;
Лявата стойност на новия връх се получава от лявата
стойност на дадения връх, като се увеличи с 1;
Дясната стойност на новия връх се получава от лявата
стойност на дадения връх, като се увеличи с 2.
2626Цветанка Георгиева
27. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ (6)
Ако трябва да се добави връх като наследник на даден връх,
който няма съществуващи наследници (например Бази от
данни), е необходимо да се изпълнят следните действия:
Всички върхове, които се намират надясно от дадения
връх трябва да увеличат лявата и дясната си стойност с 2,
както и дясната стойност на дадения връх;
Лявата стойност на новия връх се получава от лявата
стойност на дадения връх, като се увеличи с 1;
Дясната стойност на новия връх се получава от лявата
стойност на дадения връх, като се увеличи с 2.
2727Цветанка Георгиева
28. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ (7)
DECLARE @myLeft int
SELECT @myLeft = lft FROM nested_categories
WHERE CategoryName = 'Бази от данни'
UPDATE nested_categories SET rgt = rgt + 2
WHERE rgt > @myLeft
UPDATE nested_categories SET lft = lft + 2
WHERE lft > @myLeft
INSERT INTO nested_categories
(CategoryID, CategoryName, lft, rgt)
VALUES (13, 'Добиване на данни', @myLeft + 1,
@myLeft + 2)
2828Цветанка Георгиева
29. ДОБАВЯНЕ НА НОВИ ВЪРХОВЕ (8)
DECLARE @myLeft int
SELECT @myLeft = lft FROM nested_categories
WHERE CategoryName = 'Бази от данни'
UPDATE nested_categories SET rgt = rgt + 2
WHERE rgt > @myLeft
UPDATE nested_categories SET lft = lft + 2
WHERE lft > @myLeft
INSERT INTO nested_categories
(CategoryID, CategoryName, lft, rgt)
VALUES (13, 'Добиване на данни', @myLeft + 1,
@myLeft + 2)
2929Цветанка Георгиева
30. ИЗТРИВАНЕ НА ВЪРХОВЕ
Действията, които трябва да се изпълнят при изтриването на
връх, зависят от неговото местоположение в йерархията.
Изтриването на даден връх и всичките му наследници
(например Информатика) изисква:
Изтриване на дадения връх и неговите наследници;
Намаляване на левите и десните стойности на върховете,
които се намират отдясно на дадения връх, с неговата
широчина (rgt - lft + 1); предшествениците на
изтрития връх намаляват само дясната си стойност.
3030Цветанка Георгиева
31. ИЗТРИВАНЕ НА ВЪРХОВЕ (2)
Действията, които трябва да се изпълнят при изтриването на
връх, зависят от неговото местоположение в йерархията.
Изтриването на даден връх и всичките му наследници
(например Информатика) изисква:
Изтриване на дадения връх и неговите наследници;
Намаляване на левите и десните стойности на върховете,
които се намират отдясно на дадения връх, с неговата
широчина (rgt - lft + 1).
3131Цветанка Георгиева
32. ИЗТРИВАНЕ НА ВЪРХОВЕ (3)
DECLARE @myLeft int, @myRight int, @myWidth int
SELECT @myLeft = lft, @myRight = rgt,
@myWidth = rgt - lft + 1
FROM nested_categories
WHERE CategoryName = 'Информатика'
DELETE FROM nested_categories
WHERE lft BETWEEN @myLeft AND @myRight
UPDATE nested_categories SET rgt = rgt - @myWidth
WHERE rgt > @myRight
UPDATE nested_categories SET lft = lft - @myWidth
WHERE lft > @myRight
3232Цветанка Георгиева
33. ИЗТРИВАНЕ НА ВЪРХОВЕ (4)
DECLARE @myLeft int, @myRight int, @myWidth int
SELECT @myLeft = lft, @myRight = rgt,
@myWidth = rgt - lft + 1
FROM nested_categories
WHERE CategoryName = 'Информатика'
DELETE FROM nested_categories
WHERE lft BETWEEN @myLeft AND @myRight
UPDATE nested_categories SET rgt = rgt - @myWidth
WHERE rgt > @myRight
UPDATE nested_categories SET lft = lft - @myWidth
WHERE lft > @myRight
3333Цветанка Георгиева
34. ИЗТРИВАНЕ НА ВЪРХОВЕ (5)
Изтриване на връх със запазване на неговите наследници
(например Научна литература) изисква следните
действия:
Изтриване на дадения връх;
Намаляване на левите и десните стойности на вървете,
които са наследници на дадения връх, с 1;
Намаляване на левите и десните стойности на вървете,
които се намират отдясно на дадения връх, с 2;
предшествениците на изтрития връх намаляват само
дясната си стойност с 2.
3434Цветанка Георгиева
35. ИЗТРИВАНЕ НА ВЪРХОВЕ (6)
Изтриване на връх със запазване на неговите наследници
(например Научна литература) изисква следните
действия:
Изтриване на дадения връх;
Намаляване на левите и десните стойности на вървете,
които са наследници на дадения връх, с 1;
Намаляване на левите и десните стойности на вървете,
които се намират отдясно на дадения връх, с 2.
3535Цветанка Георгиева
36. ИЗТРИВАНЕ НА ВЪРХОВЕ (7)
DECLARE @myLeft int, @myRight int
SELECT @myLeft = lft, @myRight = rgt
FROM nested_categories
WHERE CategoryName = 'Научна литература'
DELETE FROM nested_categories WHERE lft = @myLeft
UPDATE nested_categories
SET rgt = rgt - 1, lft = lft - 1
WHERE lft BETWEEN @myLeft AND @myRight
UPDATE nested_categories SET rgt = rgt - 2
WHERE rgt > @myRight
UPDATE nested_categories SET lft = lft - 2
WHERE lft > @myRight
3636Цветанка Георгиева
37. ИЗТРИВАНЕ НА ВЪРХОВЕ (8)
DECLARE @myLeft int, @myRight int
SELECT @myLeft = lft, @myRight = rgt
FROM nested_categories
WHERE CategoryName = 'Научна литература'
DELETE FROM nested_categories WHERE lft = @myLeft
UPDATE nested_categories
SET rgt = rgt - 1, lft = lft - 1
WHERE lft BETWEEN @myLeft AND @myRight
UPDATE nested_categories SET rgt = rgt - 2
WHERE rgt > @myRight
UPDATE nested_categories SET lft = lft - 2
WHERE lft > @myRight
3737Цветанка Георгиева
38. 3838Цветанка Георгиева
Цветанка Георгиева-Трифонова, 2017
Някои права запазени.
Презентацията е достъпна под лиценз Creative Commons,
Признание-Некомерсиално-Без производни,
https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode