WordPress Kitchen 2014 - Дмитрий Корельский: Ангулярность WordPress бытияWordCamp KyivОт истоков JS MVC фреймворков и до создания WordPress-проектов с использованием Angular.js. Или как одна технология может изменить ваш взгляд на WordPress разработку.
Caching on highload Drupal site - Alexander ShumenkoDrupalCampDNРассмотрим создание тегированной системы кеширования сущностей для high load сайта на Drupal. В ходе доклада будут рассмотрены наиболее интересные моменты реализации (построение цепочки тегов) так же рассмотрены проблемы и способы их решения.
Работа с БД в Drupal 7Eugene FidelinЛекция для студентов НТУ ХПИ. Рассказывает основы работы с БД в Drupal 7.
Рассмотрены различные виды запросов, использование PDO.
Разработка на Perl под Raspberry PIIlya ChesnokovДоклад о разработке (а главное - оптимизации) программы на Perl под Raspberry PI.
Наглядно показывает, что в Perl есть немало возможностей, а также инструментов, которые позволяют делать программы быстрее и эффективнее - используя как преимущества самого языка, так и оптимизацию алгоритма программы.
Что нового в Perl? 5.10 — 5.16Anatoly SharifulinПеревод презентации @rjbs "What's new in Perl? v5.10 — v5.16" http://www.slideshare.net/rjbs/whats-new-in-perl-v510-v516
Entity возрождение легенды. Исай РусланDrupalSibИсай Руслан выступил с темой “Entity. Возрождение легенды” на Drupal Cafe #18
Видео с презентации вы сможете увидеть, перейдя по ссылке https://youtu.be/JkXuirPcBPE?list=PLtUZRIj1OWYzCGb3OCYMVYqnrJ-EpH0Ot
Лекция #5. Введение в язык программирования Python 3Яковенко КириллWeb-программирование
Лекция #5. Введение в язык программирования Python 3
Цикл лекций читается в Омском государственном университете им. Ф.М.Достоевского на факультете компьютерных наук.
Лектор: Яковенко Кирилл Сергеевич.
Кирилл Мавродиев, Intel – Обзор современных возможностей по распараллеливанию...Media GorodThis document discusses Intel Parallel Studio 2011. It provides an overview of the key components of Intel Parallel Studio 2011, including Intel Parallel Composer, Intel Parallel Advisor, Intel Parallel Inspector, and Intel Parallel Amplifier. Intel Parallel Composer includes optimization tools like the Intel Cilk Plus compiler and array notations for data parallelism. Intel Parallel Advisor provides guidance on designing parallel applications. Intel Parallel Inspector checks for memory and threading errors. Intel Parallel Amplifier tunes application performance.
Работа с БД в Drupal 7Eugene FidelinЛекция для студентов НТУ ХПИ. Рассказывает основы работы с БД в Drupal 7.
Рассмотрены различные виды запросов, использование PDO.
Разработка на Perl под Raspberry PIIlya ChesnokovДоклад о разработке (а главное - оптимизации) программы на Perl под Raspberry PI.
Наглядно показывает, что в Perl есть немало возможностей, а также инструментов, которые позволяют делать программы быстрее и эффективнее - используя как преимущества самого языка, так и оптимизацию алгоритма программы.
Что нового в Perl? 5.10 — 5.16Anatoly SharifulinПеревод презентации @rjbs "What's new in Perl? v5.10 — v5.16" http://www.slideshare.net/rjbs/whats-new-in-perl-v510-v516
Entity возрождение легенды. Исай РусланDrupalSibИсай Руслан выступил с темой “Entity. Возрождение легенды” на Drupal Cafe #18
Видео с презентации вы сможете увидеть, перейдя по ссылке https://youtu.be/JkXuirPcBPE?list=PLtUZRIj1OWYzCGb3OCYMVYqnrJ-EpH0Ot
Лекция #5. Введение в язык программирования Python 3Яковенко КириллWeb-программирование
Лекция #5. Введение в язык программирования Python 3
Цикл лекций читается в Омском государственном университете им. Ф.М.Достоевского на факультете компьютерных наук.
Лектор: Яковенко Кирилл Сергеевич.
Кирилл Мавродиев, Intel – Обзор современных возможностей по распараллеливанию...Media GorodThis document discusses Intel Parallel Studio 2011. It provides an overview of the key components of Intel Parallel Studio 2011, including Intel Parallel Composer, Intel Parallel Advisor, Intel Parallel Inspector, and Intel Parallel Amplifier. Intel Parallel Composer includes optimization tools like the Intel Cilk Plus compiler and array notations for data parallelism. Intel Parallel Advisor provides guidance on designing parallel applications. Intel Parallel Inspector checks for memory and threading errors. Intel Parallel Amplifier tunes application performance.
Примеры решения типичных задач за рамками ядра Yii2Paul KlimovРассмотрим сравнительно сложные, и в то же время, часто возникающие, задачи, для которых ядро Yii не дает готового решения. Посмотрим как из отдельных моделей ActiveRecord собирать единые сущности, и как разбивать большие модели на составляющие. Разберем как правильно сохранять файлы и как сэкономить на обработчиках событий и поведениях
- Интернационализация сущностей в базе данных;
- Обработка “ролей” в реляционных базах данных;
- Работа с файлами;
- Вложенные модели;
- Trait вместо Behavior.
50. Виды наследований1. Одиночное наследование:idpidid INTEGERidpididpidpididpid INTEGER…idpididpididpididpididpid1. Множественное наследование:idpididpididpididpididpidid INTEGER?idpidsidpidspidsidpidsidpidsid?pid INTEGER[]…idpidsidpidsidpidsidpidsidpidsИерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
89. Подчиненная ветка;Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
94. Использование Adjacency ListПолучение смежных узлов:Родительский узел:SELECT * FROMmy_treeWHERE id = [pid];Подчиненные узлы:SELECT * FROMmy_treeWHEREpid = [id];Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
95. Использование Adjacency ListПолучение родительской ветви:С использованием JOIN:SELECT * FROMmy_treeAS l4 JOINmy_treeAS l3 ON l3.id = l4.pid JOINmy_treeAS l2 ON l2.id = l3.pid JOINmy_treeAS l1 ON l1.id = l2.pid ... WHERE l4.id = [item.pid];С использованием UNION:SELECT l1.*, 1 AS levelFROMmy_treeAS l1 WHERE l1.id = [item.pid]UNIONSELECT l2.*, 2 AS level FROMmy_treeAS l1 JOINmy_treeAS l2 ON l2.id = l1.pid WHERE l1.id = [item.pid]UNIONSELECT l3.*, 3 AS level FROMmy_treeAS l1 JOINmy_treeAS l2 ON l2.id = l1.pid JOINmy_treeAS l3 ON l3.id = l2.pid WHERE l1.id = [item.pid]...ORDERBY level DESC;Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
96. Использование Adjacency ListПолучение родительской ветви:С использованием WITH RECURSIVE (PostgreSQL 8.4):WITH RECURSIVEparentsAS (SELECT *, ARRAY[t.id] AS exist, FALSE AS cycle FROMmy_treeAS t WHERE id = [item.pid]UNION ALL SELECT t.*, exist || t.id, t.id = ANY(exist) FROMparentsAS p, my_treeAS t WHERE t.id = p.pid AND NOT cycle ) SELECT * FROMparents WHERE NOT cycle LIMIT[max_deep];WITH RECURSIVE мы создаем рекурсивный подзапрос parents.Первый запрос рекурсии, в нем указываем точку отсчета. Второй запрос, собственно, рекурсивный запрос. Поле exist - массив уже полученных id, который мы проверяем в поле cycle, что бы не уйти в бесконечную рекурсию. LIMIT ограничивает глубину выборки ветки, так как родитель у узла может быть только лишь один.Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
97. Использование Adjacency ListПолучение родительской ветви (на уровне приложения):Рекурсивная функция:...subparent_recurse {my%params = @_;# Текущая глубина рекурсии$params{deep} ||= 1;# Хеш ранее выбранных узлов$params{exist} ||= {};# Возвращаем пустой список если превысили максимальную заданную глубину рекурсииreturn () if$params{deep} && $params{max_deep} && $params{deep} > $params{max_deep};# делаем запрос к базе данных на поллучение следующего узлаmy$query = 'SELECT * FROM my_tree WHERE id = ' . $params{pid};my$sth = $dbh->prepare($query); $sth->execute;my$item = $sth->fetchrow_hashref;$sth->finish;# Объявляем внутренний список узлов – родителейmy@parents= ();# Если узел найден и у него явно есть родитель, тоif($item&& $item->{pid}) {# Для начала проверим, а не выбирали ли мы уже такой родительский узелreturn () if$params{exist}->{$item->{pid}};# Не выбирали, тогда добавляем в хеш$params{exist}->{$item->{id}} = 1;# И вызываем снова рекурсивную функцию@parents = &parent_recurse(pid => $item->{pid},max_deep => $params{max_deep},deep => $params{deep} + 1,exist => $params{exist} ); }# Добавлем выбранный узел к массиву, если естьpush@parents, $itemif$item;# Возвращаем список выбранных узловreturn@parents;}...my@parents = &parent_recurse(pid => $item->{pid}, max_deep => 2);...Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
98. Использование Adjacency ListПолучение родительской ветви (на уровне приложения):Динамический массив:...# Объявляем пустой список родителейmy@parents= ();# Объявляем хеш уже полученных узлов, и добавляем в него id текущего узлаmy%exist= ($item->{id} => 1);# Объявляем динамический массив и вносим в него текущий узелmy@while = ($item);# Максимальная глубина выборкиmy$max_deep = 3;# Текущая глубина выборкиmy$deep = 1;# В цикле отрезаем первый эмемент динамического массива до тех пор пока это возможноwhile (my$item = shift @while && $deep <= $max_deep) {# Прерываем цикл, если узла явно нет родителя или такого родителя мы уже получалиlastif!$item->{pid} || $exist{$item->{pid}};# Делаем запрос к базе данныхmy$query = 'SELECT * FROM my_tree WHERE id = ' . $item->{pid};my$sth = $dbh->prepare($query); $sth->execute;my$parent = $sth->fetchrow_hashref;$sth->finish;# Прерываем цикл, если узел не получилиlastunless$parent;# Добавляем узел в массив родителейpush@parents, $parent;# Добавляем id узла в хеш полученных узлов$exist{$parent->{id}} = 1;# Добавляем узел в динамический массивpush@while, $parent;# Инкрементим текущую глубину$deep++;}...Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
99. Использование Adjacency ListПолучение родительской ветви:Хранимая процедура PostgreSQL:CREATE OR REPLACE FUNCTION "public"."get_parents" (pid_in INTEGER,deep INTEGER) RETURNS SETOF "public"."my_tree" AS$body$DECLAREexist_ids INTEGER[] := ARRAY[0]; -- Для пустого массива плохо работает ALLpid_now INTEGER := pid_in; -- Текущий piddeep_now INTEGER := deep; -- Текущаа глубинаitemmy_tree;BEGINWHILEpid_nowIS NOT NULL AND pid_now > 0 ANDpid_now <> ALL (exist_ids) AND(deep_nowIS NULL OR deep_now > 0)LOOPSELECT * INTOitemFROMmy_treeWHEREid = pid_now;IFitem.idIS NULL THENEXIT;END IF;RETURN NEXT item;pid_now := item.pid;exist_ids := exist_ids || item.id;IFdeep_nowIS NOT NULL THEN deep_now := deep_now – 1;END IF;END LOOP;RETURN;END;$body$LANGUAGE 'plpgsql';-- Для красоты добавим функцию с одним передаваемым параметромCREATE OR REPLACE FUNCTION "public"."get_parents" (pid_in INTEGER) RETURNSSETOF "public"."my_tree" AS$body$SELECT * FROMget_parents( $1, NULL );$body$LANGUAGE'sql';Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
100. Использование Adjacency ListПолучение родительской ветви:Хранимая процедура MySQL:CREATE DEFINER = CURRENT_USER PROCEDURE `get_parents`( IN pid_in INTEGER, IN max_deep INTEGER )BEGINDECLAREid_now INTEGER;DECLAREpid_now INTEGER DEFAULT pid_in;DECLARE field1_now TEXT;DECLAREexist TEXT DEFAULT '|';WHILEpid_now > 0 ANDexistNOT LIKE CONCAT('%|', pid_now, '|%') AND (max_deepIS NULL OR max_deep > 0)DOSELECT * INTOid_now, pid_now, field1_nowFROMmy_treeWHEREid = pid_now;SELECTid_now, pid_now, field1_now;IF (max_deepIS NOT NULL)THENSETmax_deep = max_deep - 1;END IF;SETexist = CONCAT(exist, id_now, '|'); END WHILE;END;Примечание: Возвращается несколько result set.Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
101. Использование Adjacency ListПолучение дочерней ветви:С использованием WITH RECURSIVE (PostgreSQL 8.4):WITH RECURSIVE childrenAS (SELECT *,pid || '|' || [order_field]ASord, ARRAY[id] ASexist, FALSE AScycleFROMmy_treeWHEREpid = [item.id]UNION ALLSELECTt.*,ord || '.' || t.pid || '|' || t.[order_field],exist || t.id,t.id = ANY(exist)FROMchildren AS c,my_tree AS tWHEREt.pid = c.idANDNOTcycleANDarray_length(exist, 1) < [max_deep]) SELECT * FROMchildrenWHERE NOT cycleORDER BY ordLIMIT[limit];Где: [order_field] - поле сортировки в пределах подчинения;
102. [item.id] - ID узла от которого производится выборка;
104. [limit] - количество выбираемых строк;Основной особенностью этого запроса является дополнительное поле path, которое практически является Materializedpath, за исключением того, что мы добавляем в него дополнительное поле сортировки текущего узла.Причем защита от зацикливания (поля exist и cycle) локализована в пределах отдельных ветвей, поэтому это хоть и предохранит от бесконечного зацикливания, но позволит повторно выбрать строки, так что будте внимательны.Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
105. Использование Adjacency ListПолучение дочерней ветви (на уровне приложения):Рекурсивная функция:...subchild_recurse {my%params= @_;# Текущая глубина рекурсии$params{deep} ||= 1;# Хеш ранее выбранных узлов$params{exist} ||= {};# Возвращаем пустой список если превысили максимальную заданную глубину рекурсииreturn () if$params{deep} && $params{max_deep} && $params{deep} > $params{max_deep};# Объявляем внутренний список узлов – потомковmy@children = ();# делаем запрос к базе данных на получение списка подчиненных узловmy$query = 'SELECT * FROM my_tree WHERE pid = ' . $params{pid} . ($params{order} ? ' ORDER BY ' . $params{order} : '');my$sth = $dbh->prepare($query); $sth->execute;while (my$item = $sth->fetchrow_hashref) {# Для начала проверим, а не выбирали ли мы уже такой узелnext () if$params{exist}->{$item->{id}};# Не выбирали, тогда добавляем в хеш$params{exist}->{$item->{id}} = 1;# Добавлем выбранный узел к массивуpush@children, $item;# Вызываем снова рекурсивную функцию для получения подчиненных узлов текущего узлаmy@children_deep = &child_recurse(pid => $item->{id}, max_deep => $params{max_deep}, order => $params{order},deep => $params{deep} + 1, exist => $params{exist},);# Добавляем список подчиненных узлов текущего узлаpush@children, @children_deep; }$sth->finish;# Возвращаем список выбранных узлов return@children;}my@children = &child_recurse(pid => $item->{id}, max_deep => 5, order => 'id');...Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
106. Использование Adjacency ListПолучение дочерней ветви (на уровне приложения):Оптимизация выборки:Ввести денормализацию таблицы создав дополнительное поле счетчика потомков. В этом случае можно будет проверять наличие потомков и делать или нет запрос на их получение. Это решение рассмотрено более детально ниже;Производить выборки не построчно, а списочно, для каждого уровня вложенности. Это решение подробно рассмотрим здесь;SELECTchildren.*FROMmy_treeASchildrenJOINmy_treeASparentsONparents.id = children.pidWHEREchildren.pid = ANY([parents_array])ORDER BYparents.[order_field], children.[order_field];Где:[parents_array] - массив id родительских узлов;[order_field] - поле сортировки;Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
107. Использование Adjacency ListПолучение дочерней ветви (на уровне приложения):Динамический массив:...my$max_deep= 5;my$order= 'field1‘;my$limit= 20; my@children= (); my@while= ($item); my%exist= (); my%indexes= (); my$skew= 0; my$pids= []; my$deep_now= 1; while (my$child= shift@while) {nextif$exist{$child->{id}};$exist{$child->{id}} = 1;push@$pids, $child->{id};unless (defined$indexes{$child->{pid} || 'NULL'}) {if ($childne$item) {push@children, $child;$indexes{$child->{id}} = $#children; } } else {splice@children, $indexes{$child->{pid}} + $skew+ 1, 0 , ($child); $indexes{$child->{id}} = $indexes{$child->{pid}} + $skew+ 1;$skew++; }unless ($while[0]) {$skew= 0;$deep_now++;lastif$max_deep&& $deep_now> $max_deep;my$query= 'SELECT children.* FROM my_tree AS childrenJOIN my_tree AS parents ON parents.id = children.pidWHERE children.pid = ANY(?) ORDER BY parents.’.$order.', children.’.$order.($limit ? ' LIMIT ‘.$limit : '');my$sth= $dbh->prepare($query); $sth->execute($pids);while (my$child= $sth->fetchrow_hashref) {push@while, $child}$sth->finish; }}...Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
109. Денормализация (счетчики и уровень).Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
110. Управление Adjacency ListКонтроль подчиненности:Триггер PostgreSQL 8.4 и выше:CREATE OR REPLACE FUNCTION "public"."my_tree_update_trigger" ()RETURNStriggerAS$body$DECLAREtmp_id INTEGER;BEGIN-- Если произошло изменение родителя узлаIFNEW.pidIS NOT NULL AND (NEW.pid <> OLD.pidOROLD.pidIS NULL) THEN-- Пытаемся найти в родителькой ветки нового родителя текущий узелWITH RECURSIVE parentsAS (SELECTt.id, t.pid, ARRAY[t.id] AS exist, FALSE AS cycleFROMmy_treeAStWHEREid = NEW.pidUNION ALL SELECT t.id, t.pid, exist || t.id, t.id = ANY(exist)FROMparentsASp, my_treeAStWHEREt.id = p.pidAND NOT p.cycle )SELECTidINTOtmp_idFROMparentsWHEREid = NEW.idAND NOT cycleLIMIT 1;-- Узел найден, следовательно родителя назначить не можемIFtmp_idIS NOT NULL THENRAISE NOTICE 'Нельзя ставить потомком родителя!';NEW.pid := OLD.pid;END IF;END IF;RETURN NEW;END;$body$LANGUAGE 'plpgsql';CREATE TRIGGER "my_tree_update" BEFORE UPDATEON "public"."my_tree" FOR EACH ROWEXECUTE PROCEDURE "public"."my_tree_update_trigger"();Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
111. Управление Adjacency ListКонтроль подчиненности:Триггер PostgreSQL ниже 8.4:CREATE OR REPLACE FUNCTION "public"."my_tree_update_trigger" ()RETURNStriggerAS$body$DECLAREtmp_id INTEGER;BEGIN-- Если произошло изменение родителя узлаIFNEW.pidIS NOT NULL AND (NEW.pid <> OLD.pid OR OLD.pidIS NULL) THEN-- Пытаемся найти в родителькой ветки нового родителя текущий узелSELECT idINTOtmp_idFROMget_parents(NEW.pid) WHEREid = NEW.id LIMIT 1;-- Узел найден, следовательно родителя назначить не можемIFtmp_idIS NOT NULL THENRAISE NOTICE 'Нельзя ставить потомком родителя!';NEW.pid := OLD.pid;END IF;END IF;RETURN NEW;END;$body$LANGUAGE 'plpgsql';CREATE TRIGGER "my_tree_update" BEFORE UPDATEON "public"."my_tree" FOR EACH ROWEXECUTE PROCEDURE "public"."my_tree_update_trigger"();Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
112. Управление Adjacency ListДенормализацияcounter и level:Триггер на INSERT (PostgreSQL):CREATE OR REPLACE FUNCTION "public"."my_tree_insert_trigger" ()RETURNStrigger AS$body$DECLAREparentmy_tree;BEGIN-- Что денормализовано, то ставить вручную нельзяNEW.counter := 0;NEW.level := 0;-- Если определен pid тогда обновляем счетчик родителяIFNEW.pidIS NOT NULL ORNEW.pid > 0 THEN-- Сразу вернем результат обновления родителя-- Финт ушами с CASE при обновлении счетчика из-за того что NULL + 1 = NULL, -- поэтому эти поля лучше сразу делать NOT NULL, а сейчас перестрахуемсяUPDATEmy_treeSETcounter = CASE WHEN counterIS NULL THEN 1 ELSEcounter + 1 ENDWHEREid = NEW.pidRETURNING * INTOparent;-- Проверим существование родителя, без отмены операцииIFparent.idIS NULL THENRAISE NOTICE 'ОШИБКА! Родителя с таким ID нет (%)', NEW;NEW.pid := 0;ELSE-- Устанавливаем значение level для вставляемого узлаNEW.level := CASE WHEN parent.levelIS NULL OR parent.level = 0 THEN 1 ELSENEW.level + 1 END;END IF;END IF;RETURN NEW;END;$body$LANGUAGE 'plpgsql';CREATE TRIGGER "my_tree_insert" BEFORE INSERT ON "public"."my_tree" FOR EACH ROW EXECUTE PROCEDURE "public"."my_tree_insert_trigger"();Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
113. Управление Adjacency ListДенормализацияcounter и level:Триггер на UPDATE (PostgreSQL):CREATE OR REPLACE FUNCTION "public"."my_tree_update" ()RETURNStrigger AS$body$DECLAREparentmy_tree;childmy_tree;level_skew INTEGER;pids INTEGER[];tmp_pids INTEGER[];exist_update INTEGER[];BEGIN-- Опять же для предотвращения сравнения с NULL ставим 0IFOLD.pidIS NULL THEN OLD.pid := 0; END IF;IFNEW.pidIS NULL THEN NEW.pid := 0; END IF;IFOLD.levelIS NULL THEN OLD.level := 0; END IF;-- Если произошла смена родителяIFNEW.pid <> OLD.pidTHEN-- Уменьшаем счетчик старого родителя если он естьIFOLD.pid > 0 THEN UPDATE my_treeSETcounter = counter - 1 WHEREid = OLD.pid; END IF;-- Увеличиваем счетчик нового родителя если он естьIFNEW.pid > 0 THEN UPDATEmy_treeSETcounter = COALESCE(counter, 0) + 1 WHEREid = NEW.pidRETURNING * INTOparent;-- Проверяем существование родителяIFparent.idIS NULL THENRAISE NOTICE 'ОШИБКА! Родителя с таким ID нет (%)', NEW;NEW.level := 0;NEW.pid := 0;ELSE-- Если родитель есть то устанавливаем новый уровень узлаNEW.level := COALESCE(parent.level, 0) + 1;END IF;ELSENEW.level := 0;END IF;-- Данные по перемещаемому узлу обновили, теперь следует обновить-- level потомков перемещаемого узлаlevel_skew := NEW.level - OLD.level;...Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
114. Управление Adjacency ListДенормализацияcounter и level:Триггер на UPDATE (PostgreSQL), продолжение:...-- Смещение уровня таки естьIFlevel_skew <> 0 THENpids := ARRAY[NEW.id];exist_update := ARRAY[NEW.id]; -- Пока есть узлы у которых есть потомки:WHILEpids[1] IS NOT NULL LOOPtmp_pids := ARRAY[NULL];-- Обновляем всех потомков на уровнеFORchildIN UPDATE my_treeSETlevel = level + level_skewWHEREpid = ANY (pids) ANDid <> ALL (exist_update) RETURNING *LOOP-- Поставим защиту для того, что бы невозможно было поставить узел в починение своему потомкуIFchild.id = NEW.pidTHENRAISE EXCEPTION 'Ошибка! Нельзя ставить узел в подчинение потомку! (%)', NEW;RETURN NULL;END IF;-- Если у потомка еще есть потомки, то добавляем его id в список на обновление-- следующего уровняIFchild.counterIS NOT NULL ANDchild.counter > 0 THENtmp_pids := array_prepend(child.id, tmp_pids);END IF;-- Защита от повторовexist_update := array_append(exist_update, child.id);END LOOP;pids := tmp_pids;END LOOP;END IF;END IF;RETURN NEW;END;$body$LANGUAGE 'plpgsql';CREATE TRIGGER "my_tree_update" BEFORE UPDATEON "public"."my_tree" FOR EACH ROWEXECUTE PROCEDURE "public"."my_tree_update"();Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
115. Управление Adjacency ListДенормализацияcounter и level:Триггер на DELETE (PostgreSQL) :CREATE OR REPLACE FUNCTION "public"."my_tree_delete_trigger" ()RETURNStriggerAS$body$BEGIN-- Если есть родитель, то обновляем его счетчикIFOLD.pidIS NOT NULL AND OLD.pid > 0 THENUPDATEmy_treeSETcounter = counter – 1WHEREid = OLD.pid;END IF;IFcurrent_setting('user_vars.tree_delete') = 'levelup' THENUPDATEmy_treeSETpid = OLD.pid WHERE pid = OLD.id;ELSIFcurrent_setting('user_vars.tree_delete') = 'root' THENUPDATEmy_treeSETpid = 0WHEREpid = OLD.id;ELSEIFOLD.counterIS NOT NULL AND OLD.counter > 0 THENDELETE FROM my_treeWHEREpid = OLD.id;END IF;END IF;RETURN OLD;END;$body$LANGUAGE 'plpgsql';CREATE TRIGGER "my_tree_delete" AFTER DELETEON "public"."my_tree" FOR EACH ROWEXECUTE PROCEDURE "public"."my_tree_delete_trigger"();Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
116. Управление Adjacency ListДенормализацияcounter и level:Способы удаления ветвей:1. Транзакционный:BEGIN;SELECTset_config('user_vars.tree_delete', 'levelup', TRUE);DELETE FROM my_treeWHEREid = [item.id];COMMIT;1. Не транзакционный:DELETE FROM my_treeUSING (SELECTset_config('user_vars.tree_delete', 'root', TRUE) ) ASconfWHEREid = [item.id];Иерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)
117. Вопросы?Статьи по теме: http://doc.prototypes.ru/database/trees/Сергей ТомулевичRambler, Москва, 2010Карикатуры: Сергей КорсунИерархические структуры в реляционных базах данных: Adjacency List (Смежные вершины)