CREATE TABLE `ns_tree` ( `id` int (11) NOT NULL auto_increment, `left_key` int (11) NOT NULL default '0', `right_key` int (11) NOT NULL default '0', `level` int (11) NOT NULL default '0', `parent_id` int (11) NOT NULL default '0', `tree` int (11) NOT NULL default '1', `field1` text, PRIMARY KEY (`id`) ) ENGINE = MyISAM;
CREATE TABLE `_ns_tree` ( `id` int (11) NOT NULL auto_increment, `left_key` int (11) NOT NULL default '0', `right_key` int (11) NOT NULL default '0', `level` int (11) NOT NULL default '0', `parent_id` int (11) NOT NULL default '0', `tree` int (11) NOT NULL default '1', `field1` text, PRIMARY KEY (`id`) ) ENGINE = MERGE INSERT_METHOD = LAST UNION = (`ns_tree`);
CREATE DEFINER = 'user' @ 'localhost' TRIGGER `ns_tree_before_ins_tr` BEFORE INSERT ON` ns_tree` FOR EACH ROW BEGIN SET @left_key: = 0; SET @level: = 0; - If we indicated a parent: IF NEW.parent_id IS NOT NULL AND NEW.parent_id> 0 THEN SELECT right_key, `level` + 1 INTO @left_key, @level FROM ns_tree WHERE id = NEW.parent_id AND tree = NEW.tree; END IF; - If we specified the left key: IF NEW.left_key IS NOT NULL AND NEW.left_key> 0 AND (@left_key IS NULL OR @left_key = 0) THEN SELECT id, left_key, right_key, `level`, parent_id INTO @tmp_id, @tmp_left_key, @tmp_right_key, @tmp_level, @tmp_parent_id FROM ns_tree WHERE tree = NEW.tree AND (left_key = NEW.left_key OR right_key = NEW.left_key); IF @tmp_left_key IS NOT NULL AND @tmp_left_key> 0 AND NEW.left_key = @tmp_left_key THEN SET NEW.parent_id: = @tmp_parent_id; SET @left_key: = NEW.left_key; SET @level: = @tmp_level; ELSEIF @tmp_left_key IS NOT NULL AND @tmp_left_key> 0 AND NEW.left_key = @tmp_right_key THEN SET NEW.parent_id: = @tmp_id; SET @left_key: = NEW.left_key; SET @level: = @tmp_level + 1; END IF; END IF; - If the parent or left key is not specified, or we did not find anything IF @left_key IS NULL OR @left_key = 0 THEN SELECT MAX (right_key) + 1 INTO @left_key FROM ns_tree WHERE tree = NEW.tree; IF @left_key IS NULL OR @left_key = 0 THEN SET @left_key: = 1; END IF; SET @level: = 0; SET NEW.parent_id: = 0; END IF; - Set new key values SET NEW.left_key: = @left_key; SET NEW.right_key: = @left_key + 1; SET NEW.`level`: = @level; - We form a gap in the tree UPDATE _ns_tree SET left_key = CASE WHEN left_key> = @left_key THEN left_key + 2 ELSE left_key + 0 END, right_key = right_key + 2 WHERE tree = NEW.tree AND right_key> = @left_key; END;
CREATE DEFINER = 'user' @ 'localhost' TRIGGER `ns_tree_before_upd_tr` BEFORE UPDATE ON` ns_tree` FOR EACH ROW BEGIN - Forbid to change fields, or send nasty things SET NEW.tree: = OLD.tree; SET NEW.right_key: = OLD.right_key; SET NEWlevel`: = OLD .level`; SET @return_flag: = 0; IF NEW.parent_id IS NULL THEN SET NEW.parent_id: = 0; END IF; - Check whether there are changes associated with the tree structure IF NEW.parent_id <> OLD.parent_id OR NEW.left_key <> OLD.left_key THEN - We are still rebuilding the tree, well, let's start: SET @left_key: = 0; SET @level: = 0; SET @skew_tree: = OLD.right_key - OLD.left_key + 1; - Determine where we transfer it: - If parent_id is changed: IF NEW.parent_id <> OLD.parent_id THEN - If in submission to another evil: IF NEW.parent_id> 0 THEN SELECT right_key, level + 1 INTO @left_key, @level FROM ns_tree WHERE id = NEW.parent_id AND tree = NEW.tree; - Otherwise, we transfer to the root of the tree: ELSE SELECT MAX (right_key) + 1 INTO @left_key FROM ns_tree WHERE tree = NEW.tree; SET @level: = 0; END IF; - If suddenly the parent is in the range of the node being moved, check: IF @left_key IS NOT NULL AND @left_key> 0 AND @left_key> OLD.left_key AND @left_key <= OLD.right_key THEN SET NEW.parent_id: = OLD.parent_id; SET NEW.left_key: = OLD.left_key; SET @return_flag: = 1; END IF; END IF; - If not parent_id, then left_key is changed, or if parent_id change did not give anything IF @left_key IS NULL OR @left_key = 0 THEN SELECT id, left_key, right_key, `level`, parent_id INTO @tmp_id, @tmp_left_key, @tmp_right_key, @tmp_level, @tmp_parent_id FROM ns_tree WHERE tree = NEW.tree AND (right_key = NEW.left_key OR right_key = NEW.left_key - 1) LIMIT 1; IF @tmp_left_key IS NOT NULL AND @tmp_left_key> 0 AND NEW.left_key - 1 = @tmp_right_key THEN SET NEW.parent_id: = @tmp_parent_id; SET @left_key: = NEW.left_key; SET @level: = @tmp_level; ELSEIF @tmp_left_key IS NOT NULL AND @tmp_left_key> 0 AND NEW.left_key = @tmp_right_key THEN SET NEW.parent_id: = @tmp_id; SET @left_key: = NEW.left_key; SET @level: = @tmp_level + 1; ELSEIF NEW.left_key = 1 THEN SET NEW.parent_id: = 0; SET @left_key: = NEW.left_key; SET @level: = 0; ELSE SET NEW.parent_id: = OLD.parent_id; SET NEW.left_key: = OLD.left_key; SET @return_flag = 1; END IF; END IF; - Now we know where we move the tree. - Check whether it is worth doing IF @return_flag IS NULL OR @return_flag = 0 THEN SET @skew_level: = @level - OLD .level`; IF @left_key> OLD.left_key THEN - Move up the tree SET @skew_edit: = @left_key - OLD.left_key - @skew_tree; UPDATE _ns_tree SET left_key = CASE WHEN right_key <= OLD.right_key THEN left_key + @skew_edit ELSE CASE WHEN left_key> OLD.right_key THEN left_key - @skew_tree ELSE left_key END END, `level` = CASE WHEN right_key <= OLD.right_key THEN `level` + @skew_level ELSE `level` END, right_key = CASE WHEN right_key <= OLD.right_key THEN right_key + @skew_edit ELSE CASE WHEN right_key <@left_key THEN right_key - @skew_tree ELSE right_key END END WHERE tree = OLD.tree AND right_key> OLD.left_key AND left_key <@left_key AND id <> OLD.id; SET @left_key: = @left_key - @skew_tree; ELSE - Move down the tree: SET @skew_edit: = @left_key - OLD.left_key; UPDATE _ns_tree SET right_key = CASE WHEN left_key> = OLD.left_key THEN right_key + @skew_edit ELSE CASE WHEN right_key <OLD.left_key THEN right_key + @skew_tree ELSE right_key END END, `level` = CASE WHEN left_key> = OLD.left_key THEN `level` + @skew_level ELSE `level` END, left_key = CASE WHEN left_key> = OLD.left_key THEN left_key + @skew_edit ELSE CASE WHEN left_key> = @left_key THEN left_key + @skew_tree ELSE left_key END END WHERE tree = OLD.tree AND right_key> = @left_key AND left_key <OLD.right_key AND id <> OLD.id; END IF; - Tree rebuilt, only our current node remains SET NEW.left_key: = @left_key; SET NEW.`level`: = @level; SET NEW.right_key: = @left_key + @skew_tree - 1; END IF; END IF; END;
CREATE DEFINER = 'user' @ 'localhost' TRIGGER `ns_tree_before_del_tr` AFTER DELETE ON` ns_tree` FOR EACH ROW BEGIN - Remove child nodes: DELETE FROM _ns_tree WHERE tree = OLD.tree AND left_key> OLD.left_key AND right_key <OLD.right_key; - Remove the gap in the keys: SET @skew_tree: = OLD.right_key - OLD.left_key + 1; UPDATE _ns_tree SET left_key = CASE WHEN left_key> OLD.left_key THEN left_key - @skew_tree ELSE left_key END, right_key = right_key - @skew_tree WHERE right_key> OLD.right_key AND tree = OLD.tree AND id <> OLD.id; END;
CREATE DEFINER = 'user' @ 'localhost' TRIGGER `ns_tree_before_del_tr` AFTER DELETE ON` ns_tree` FOR EACH ROW BEGIN - Remove the gap in the keys: UPDATE _ns_tree SET left_key = CASE WHEN left_key <OLD.left_key THEN left_key ELSE CASE WHEN right_key <OLD.right_key THEN left_key - 1 ELSE left_key - 2 END END, parent_id = CASE WHEN right_key <OLD.right_key AND `level` = OLD.level + 1 THEN OLD.parent_id ELSE parent_id END, `level` = CASE WHEN right_key <OLD.right_key THEN `level` - 1 ELSE `level` END, right_key = CASE WHEN right_key <OLD.right_key THEN right_key - 1 ELSE right_key - 2 END WHERE (right_key> OLD.right_key OR (left_key> OLD.left_key AND right_key <OLD.right_key)) AND tree = OLD.tree; END;
Source: https://habr.com/ru/post/63883/
All Articles