Каждую пятницу у нас на работе делают план отделу ПО. К счастью, эта участь в основном проходит мимо меня, т.к. на мне висит большая часть технической поддержки. Но вот в одну из таких пятниц очередь добралась и до меня.
Итак задание:
1)Разработать систему хранения информации для софта и его привязки к торговым объектам. При этом,
торговые объекты входят в юрлицо, а юрлицо может входить в холдинг. Получается дерево с нижним уровнем «торговый объект» и верхним «холдинг», софт же может привязываться на любом уровне этого дерева. При этом торговые объекты могут перемещаться между юрлицами, юрлица между холдингами(или вовсе быть вне холдингов) и т.д.
2)В связи с отсутствием данных для всей этой причуды, разработать web-интерфейс для операций добавления,
удаления и редактирования уровней дерева. Ну и для добавления, удаления и привязки софта к объектам дерева.
3)Выгружать полученное дерево в MongoDB согласно заданным правилам.
Довольно таки нетривиальная задача для веб-проекта, не смотря на то что звучит не сложно. Изначально я начал описывать дерево и его поведение в php. Не смотря на то что БД MySQL стоит на той же виртуальной машине, что и веб-сервер, кол-во запросов к базе меня начало смущать. Да и доработке такой скрипт очень тяжело подвергался, если его кроме меня кто дорабатывать возьмется. В итоге через несколько часов было решено отказаться от дурной идеи и начать с более глубокого изучения SQL. В интернете полно «примеров» сложных запросов, но они довольно тривиальны.
Уже зная принцип работы триггеров в MSSQL я хотел построить дерево на них, но оказалось в MySQL триггеры не поддерживают Dynamic SQL. Проще говоря, я не могу засунуть содержимое ячейки в переменную, а потом добавить столбец с именем соответствующему этой переменной в другую таблицу и т.п. С идеей триггеров пришлось распрощаться, остался вариант с процедурами и таблицами связей.
Итак было решено организовать три таблицы — три уровня дерева: холдинг, юрлицо, торговый объект. А также две таблицы связей, для связки уровней дерева. Дополнительно таблица с софтом и таблица связки объектов с их uid. Всю логику работы дерева изложить в процедурах, а ограничения задать в индексах таблиц.
В итоге получил таблица холдингов:
CREATE TABLE `holding` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `soft` varchar(255) NOT NULL DEFAULT '', `data` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`Id`), UNIQUE KEY `name` (`name`,`soft`) ) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;
Таблица юрлиц:
CREATE TABLE `jurlico` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `soft` varchar(255) NOT NULL DEFAULT '', `data` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`Id`), UNIQUE KEY `name` (`name`,`soft`) ) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;
Таблица объектов:
CREATE TABLE `object` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `soft` varchar(255) DEFAULT NULL, `data` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`Id`), UNIQUE KEY `name` (`name`,`soft`) ) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
Таблица связи холдинг-юрлицо:
CREATE TABLE `link_holding` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `holding` varchar(255) DEFAULT NULL, `jurlico` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`), UNIQUE KEY `jurlico` (`jurlico`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
Таблица связи юрлицо-объект:
CREATE TABLE `link_jurlico` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `jurlico` varchar(255) DEFAULT NULL, `object` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`), UNIQUE KEY `object` (`object`) ) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
Таблица связи объект-uid:
CREATE TABLE `link_object` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `object` varchar(255) DEFAULT NULL, `guid` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`), UNIQUE KEY `object` (`object`), UNIQUE KEY `guid` (`guid`) ) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
Таблица с софтом(изначально столбца hash не было, но потом решил его добавить. это повлияло и на разработку):
CREATE TABLE `software` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `path` varchar(255) DEFAULT NULL, `localpath` varchar(255) DEFAULT NULL, `hash` varchar(255) DEFAULT NULL, `data` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`Id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8;
Таблица uid-ов холдингов и юрлиц:
CREATE TABLE `guid_for_jur_hold` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `holding` varchar(255) DEFAULT NULL, `jurlico` varchar(255) DEFAULT NULL, `guid` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`), UNIQUE KEY `guid` (`guid`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
Первую процедуру, которую написал — это добавление софта, она пожалуй и самая простая. Позже при выгрузке понял, что нужно фиксировать удаленный софт, поэтому добавил еще одну таблицу для этого(тут ничего особенного):
CREATE TABLE `remove_soft` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
Ну и сама процедура, на которой я разобрался с принципом работы процедур, выводом необходимых параметров во временную таблицу, работе с переменными и проверку на существование индекса в таблице. С IF знакомиться не пришлось, т.к. тут все языки схожи. Ну и простейшие запросы я и до этого знал. Собственно процедура:
CREATE DEFINER=`***`@`*******` PROCEDURE `proc_software`(v_command varchar(255), v_name varchar(255), v_path varchar(255), v_localpath varchar(255)) BEGIN IF v_command = 'add' THEN IF !EXISTS(SELECT `name` FROM `software` WHERE `name`=v_name ORDER BY Id DESC LIMIT 1) THEN INSERT INTO `software` (`name`, `path`, `localpath`) VALUES (v_name, v_path, v_localpath); SET @Answer = concat(v_name, ' добавлено в список ПО!'); SET @Ctrl = concat('add'); ELSE SET @Answer = concat(v_name, ' уже существует в списоке ПО!'); SET @Ctrl = concat('removeandadd'); END IF; ELSEIF v_command = 'remove' THEN IF EXISTS(SELECT `name` FROM `software` WHERE `name`=v_name ORDER BY Id DESC LIMIT 1) THEN DELETE FROM `software` WHERE `name` = v_name; DELETE FROM `holding` WHERE `soft` = v_name; DELETE FROM `jurlico` WHERE `soft` = v_name; DELETE FROM `object` WHERE `soft` = v_name; INSERT INTO `remove_soft` (`name`) VALUES (v_name); SET @Answer = concat(v_name, ' удалено из списка ПО!'); SET @Ctrl = concat('remove'); ELSE SET @Answer = concat(v_name, ' отсутствует в списоке ПО!'); SET @Ctrl = concat('error'); END IF; ELSEIF v_command = 'update' THEN IF EXISTS(SELECT `name` FROM `software` WHERE `name`=v_name ORDER BY Id DESC LIMIT 1) THEN UPDATE `software` SET `name` = v_name, `path` = v_path, `localpath` = v_localpath where `name` like v_name; SET @Answer = concat(v_name, ' обновлено в списке ПО!'); SET @Ctrl = concat('update'); ELSE SET @Answer = concat(v_name, ' отсутствует в списоке ПО!'); SET @Ctrl = concat('error'); END IF; END IF; SELECT @Answer, @Ctrl; END;
Вышеуказанной процедурой можно добавлять, удалять и обновлять софт. Что ж перейдем к объектам. Вот тут я узнал про оператор IN в MySQL, очень полезный, я скажу, оператор. Позволяет в запросе использовать выборку полученную другим запросом(SELECT). Вот собственно процедура добавления, удаления и обновления объекта:
CREATE DEFINER=`***`@`******` PROCEDURE `proc_object`(v_command varchar(255), v_object varchar(255), v_guid varchar(255), v_jurlico varchar(255)) BEGIN IF v_command = 'add' THEN IF !EXISTS(SELECT `object` FROM `link_jurlico` WHERE `object` LIKE v_object) THEN IF !EXISTS(SELECT `object` FROM `link_object` WHERE `guid` LIKE v_guid) THEN INSERT INTO `link_jurlico` SET `object` = v_object, `jurlico` = v_jurlico; INSERT INTO `link_object` SET `object` = v_object, `guid` = v_guid; SET @Answer = concat(v_object, ' добавлено в список объектов!'); ELSE SET @Answer = concat(v_guid, ' уже принадлежит объекту!'); END IF; ELSE SET @Answer = concat(v_object, ' уже существует в списоке объектов!'); END IF; ELSEIF v_command = 'remove' THEN IF EXISTS(SELECT `object` FROM `link_jurlico` WHERE `object` LIKE v_object) THEN DELETE FROM `object` WHERE `name` = v_object; DELETE FROM `link_object` WHERE `object` = v_object; DELETE FROM `link_jurlico` WHERE `object` = v_object; SET @Answer = concat(v_object, ' удалено из списка объектов!'); ELSE SET @Answer = concat(v_object, ' отсутствует в списке объектов!'); END IF; ELSEIF v_command = 'update' THEN IF EXISTS(SELECT `object` FROM `link_jurlico` WHERE `object` LIKE v_object) THEN IF !ISNULL(v_guid) THEN UPDATE `link_object` SET `guid` = v_guid where `object` like v_object; SET @Answer = concat(v_object, ' изменен GUID!'); END IF; IF !ISNULL(v_jurlico) THEN UPDATE `link_jurlico` SET `jurlico` = v_jurlico where `object` like v_object; DELETE FROM `object` WHERE `name` LIKE v_object AND `soft` IN (SELECT `soft` FROM `jurlico` WHERE `name` LIKE v_jurlico); SET @Answer = concat(@Answer, v_object, ' изменено юрлицо!'); END IF; ELSE SET @Answer = concat(v_object, ' отсутствует в списке объектов!'); END IF; END IF; SELECT @Answer; END;
Т.к. юрлица у нас существуют в связке с объектом и создаются процедурой выше, осталось создать холдинги. Что ж еще больше вложенных запросов, отточим навык:
CREATE DEFINER=`****`@`**********` PROCEDURE `proc_holding`(v_command varchar(255), v_holding varchar(255), v_jurlico varchar(255)) BEGIN IF v_command = 'add' THEN IF EXISTS(SELECT `jurlico` FROM `link_jurlico` WHERE `jurlico`=v_jurlico ORDER BY Id DESC LIMIT 1) THEN IF (!EXISTS(SELECT `holding` FROM `link_holding` WHERE `jurlico`=v_jurlico AND `holding`=v_holding ORDER BY Id DESC LIMIT 1) AND (v_holding <> '')) THEN IF !EXISTS(SELECT `holding` FROM `link_holding` WHERE `jurlico`=v_jurlico ORDER BY Id DESC LIMIT 1) THEN INSERT INTO `link_holding` (`holding`, `jurlico`) VALUES (v_holding, v_jurlico); DELETE FROM `jurlico` WHERE `name` LIKE v_jurlico AND `soft` IN (SELECT `soft` FROM `holding` WHERE `name` LIKE v_holding); DELETE FROM `object` WHERE `name` IN (SELECT `object` FROM `link_jurlico` WHERE `jurlico` LIKE v_jurlico) AND `soft` IN (SELECT `soft` FROM `holding` WHERE `name` LIKE v_holding); SET @Answer = concat(v_jurlico, ' добавлен в список холдинга ', v_holding, '!'); ELSE UPDATE `link_holding` SET `holding` = v_holding where `jurlico` like v_jurlico; DELETE FROM `jurlico` WHERE `name` LIKE v_jurlico AND `soft` IN (SELECT `soft` FROM `holding` WHERE `name` LIKE v_holding); DELETE FROM `object` WHERE `name` IN (SELECT `object` FROM `link_jurlico` WHERE `jurlico` LIKE v_jurlico) AND `soft` IN (SELECT `soft` FROM `holding` WHERE `name` LIKE v_holding); SET @Answer = concat(v_jurlico, ' добавлен в список холдинга ', v_holding, '!'); END IF; ELSE IF (v_holding <> '') THEN SET @Answer = concat(v_jurlico, ' уже назначено холдингу ', v_holding, '!'); ELSE DELETE FROM `link_holding` WHERE `jurlico` = v_jurlico; SET @Answer = concat(v_jurlico, ' удалено из холдинга!'); END IF; END IF; ELSE SET @Answer = concat('Не существует ни одного объекта с юрлицом ', v_jurlico, '!'); END IF; ELSEIF v_command = 'remove' THEN IF EXISTS(SELECT `holding` FROM `link_holding` WHERE `holding`=v_holding ORDER BY Id DESC LIMIT 1) THEN DELETE FROM `link_holding` WHERE `holding` = v_holding; SET @Answer = concat(v_jurlico, ' удален из холдинга ', v_holding, '!'); # DELETE FROM `holding` WHERE `name` = v_holding; ELSE SET @Answer = concat('Холдинг ', v_holding, ' не существует!'); END IF; END IF; SELECT @Answer; END;
Ну а т.к. позже оказалось что нужно(по факту может и не нужно, но пусть будет) добавим процедуру, которая будет связывать uid и холдинг или юрлицо:
CREATE DEFINER=`****`@`********` PROCEDURE `proc_guid_to`(v_to varchar(255), v_toval varchar(255), v_guid varchar(255)) BEGIN IF v_to = 'holding' THEN IF EXISTS(SELECT `holding` FROM `link_holding` WHERE `holding` LIKE v_toval) THEN IF (!EXISTS(SELECT `guid` FROM `guid_for_jur_hold` WHERE `guid` LIKE v_guid) AND !EXISTS(SELECT `guid` FROM `link_object` WHERE `guid` LIKE v_guid)) THEN IF EXISTS(SELECT `holding` FROM `guid_for_jur_hold` WHERE `holding` LIKE v_toval) THEN UPDATE `guid_for_jur_hold` SET `guid` = v_guid where `holding` like v_toval; SET @Answer = concat(v_guid, ' обновлен холдингу ', v_toval, '!'); ELSE INSERT INTO `guid_for_jur_hold` SET `holding` = v_toval, `guid` = v_guid; SET @Answer = concat(v_guid, ' добавлен холдингу ', v_toval, '!'); END IF; ELSE SET @Answer = concat(v_guid, ' уже существует!'); END IF; ELSE SET @Answer = concat('Холдингу ', v_toval, ' не присвоено ни одно юрлицо!'); END IF; ELSEIF v_to = 'jurlico' THEN IF EXISTS(SELECT `jurlico` FROM `link_jurlico` WHERE `jurlico` LIKE v_toval) THEN IF (!EXISTS(SELECT `guid` FROM `guid_for_jur_hold` WHERE `guid` LIKE v_guid) AND !EXISTS(SELECT `guid` FROM `link_object` WHERE `guid` LIKE v_guid)) THEN IF EXISTS(SELECT `jurlico` FROM `guid_for_jur_hold` WHERE `jurlico` LIKE v_toval) THEN UPDATE `guid_for_jur_hold` SET `guid` = v_guid where `jurlico` like v_toval; SET @Answer = concat(v_guid, ' обновлен юрлицу ', v_toval, '!'); ELSE INSERT INTO `guid_for_jur_hold` SET `jurlico` = v_toval, `guid` = v_guid; SET @Answer = concat(v_guid, ' добавлен юрлицу ', v_toval, '!'); END IF; ELSE SET @Answer = concat(v_guid, ' уже существует!'); END IF; ELSE SET @Answer = concat('Юрлицу ', v_toval, ' не присвоен ни один объект!'); END IF; END IF; SELECT @Answer; END;
Ну и самая большая процедура, привязка софта к уровням дерева(по возможности отлавливал ошибки на уровне SQL, в крайнем случае можно было бы их отловить на уровне передачи в функцию из php):
CREATE DEFINER=`******`@`********` PROCEDURE `proc_soft_to`(v_command varchar(255), v_to varchar(255), v_toval varchar(255), v_soft varchar(255)) BEGIN IF EXISTS(SELECT `name` FROM `software` WHERE `name`=v_soft ORDER BY Id DESC LIMIT 1) THEN IF v_command = 'add' THEN IF v_to = 'object' THEN IF EXISTS(SELECT `object` FROM `link_jurlico` WHERE `object`=v_toval ORDER BY Id DESC LIMIT 1) THEN SELECT `jurlico` FROM `link_jurlico` WHERE `object`=v_toval ORDER BY Id DESC LIMIT 1 INTO @Jurlico; SELECT `holding` FROM `link_holding` WHERE `jurlico`=@Jurlico ORDER BY Id DESC LIMIT 1 INTO @Holding; IF (!EXISTS(SELECT `name` FROM `holding` WHERE `name`=@Holding AND `soft`=v_soft) AND !EXISTS(SELECT `name` FROM `jurlico` WHERE `name`=@Jurlico AND `soft`=v_soft)) THEN INSERT INTO `object` (`name`, `soft`) VALUES (v_toval, v_soft); SET @Answer = concat(v_soft, ' добавлен в список ПО объекта ', v_toval, '!'); ELSE SET @Answer = concat(v_soft, ' уже добавлен юрлицу или холдингу!'); END IF; ELSE SET @Answer = concat(v_toval, ' отсутствует в списке объектов!'); END IF; ELSEIF v_to = 'jurlico' THEN IF EXISTS(SELECT `jurlico` FROM `link_jurlico` WHERE `jurlico`=v_toval ORDER BY Id DESC LIMIT 1) THEN SELECT `holding` FROM `link_holding` WHERE `jurlico`=v_toval ORDER BY Id DESC LIMIT 1 INTO @Holding; IF !EXISTS(SELECT `name` FROM `holding` WHERE `name`=@Holding AND `soft`=v_soft) THEN INSERT INTO `jurlico` (`name`, `soft`) VALUES (v_toval, v_soft); DELETE FROM `object` WHERE `name` IN (SELECT `object` FROM `link_jurlico` WHERE `jurlico` LIKE v_toval) AND `soft` LIKE v_soft; SET @Answer = concat(v_soft, ' добавлен в список ПО юрлица ', v_toval, '!'); ELSE SET @Answer = concat(v_soft, ' уже добавлен холдингу!'); END IF; ELSE SET @Answer = concat(v_toval, ' отсутствует в списке юрлиц!'); END IF; ELSEIF v_to = 'holding' THEN IF EXISTS(SELECT `holding` FROM `link_holding` WHERE `holding`=v_toval ORDER BY Id DESC LIMIT 1) THEN INSERT INTO `holding` (`name`, `soft`) VALUES (v_toval, v_soft); DELETE FROM `object` WHERE `name` IN (SELECT `object` FROM `link_jurlico` WHERE `jurlico` IN (SELECT `jurlico` FROM `link_holding` WHERE `holding` LIKE v_toval)) AND `soft` LIKE v_soft; DELETE FROM `jurlico` WHERE `name` IN (SELECT `jurlico` FROM `link_holding` WHERE `holding` LIKE v_toval) AND `soft` LIKE v_soft; SET @Answer = concat(v_soft, ' добавлен в список ПО холдинга ', v_toval, '!'); ELSE SET @Answer = concat(v_toval, ' отсутствует в списке холдингов!'); END IF; END IF; ELSEIF v_command = 'remove' THEN IF v_to = 'object' THEN IF EXISTS(SELECT `object` FROM `link_jurlico` WHERE `object`=v_toval ORDER BY Id DESC LIMIT 1) THEN SELECT `name` FROM `holding` WHERE `name` IN (SELECT `holding` FROM `link_holding` WHERE `jurlico` IN (SELECT `jurlico` FROM `link_jurlico` WHERE `object` LIKE v_toval)) AND `soft` = v_soft INTO @V_holding; IF EXISTS(SELECT @V_holding) THEN INSERT INTO `jurlico` (`name`, `soft`) SELECT `jurlico`,v_soft FROM `link_holding` WHERE `holding` LIKE @V_holding; DELETE FROM `holding` WHERE `name` LIKE @V_holding AND `soft` LIKE v_soft; END IF; SELECT `name` FROM `jurlico` WHERE `name` IN (SELECT `jurlico` FROM `link_jurlico` WHERE `object` LIKE v_toval) AND `soft` = v_soft INTO @V_jurlico; IF EXISTS(SELECT @V_jurlico) THEN INSERT INTO `object` (`name`, `soft`) SELECT `object`,v_soft FROM `link_jurlico` WHERE `jurlico` LIKE @V_jurlico; DELETE FROM `jurlico` WHERE `name` LIKE @V_jurlico AND `soft` LIKE v_soft; END IF; DELETE FROM `object` WHERE `name` LIKE v_toval; SET @Answer = concat(v_soft, ' удален из списка ПО объекта ', v_toval, '!'); ELSE SET @Answer = concat(v_toval, ' отсутствует в списке объектов!'); END IF; ELSEIF v_to = 'jurlico' THEN IF EXISTS(SELECT `jurlico` FROM `link_jurlico` WHERE `jurlico`=v_toval ORDER BY Id DESC LIMIT 1) THEN IF EXISTS(SELECT `name` FROM `holding` WHERE `name` IN (SELECT `holding` FROM `link_holding` WHERE `jurlico` LIKE v_toval) AND `soft` = v_soft) THEN INSERT INTO `jurlico` (`name`, `soft`) SELECT `jurlico`,v_soft FROM `link_holding` WHERE `holding` IN (SELECT `holding` FROM `link_holding` WHERE `jurlico` LIKE v_toval) AND `jurlico` <> v_toval; END IF; DELETE FROM `object` WHERE `name` IN (SELECT `object` FROM `link_jurlico` WHERE `jurlico` LIKE v_toval) AND `soft` LIKE v_soft; DELETE FROM `jurlico` WHERE `name` LIKE v_toval AND `soft` LIKE v_soft; DELETE FROM `holding` WHERE `name` IN (SELECT `holding` FROM `link_holding` WHERE `jurlico` LIKE v_toval) AND `soft` LIKE v_soft; SET @Answer = concat(v_soft, ' удален из списка ПО юрлица ', v_toval, '!'); ELSE SET @Answer = concat(v_toval, ' отсутствует в списке юрлиц!'); END IF; ELSEIF v_to = 'holding' THEN IF EXISTS(SELECT `holding` FROM `link_holding` WHERE `holding`=v_toval ORDER BY Id DESC LIMIT 1) THEN DELETE FROM `object` WHERE `name` IN (SELECT `object` FROM `link_jurlico` WHERE `jurlico` IN (SELECT `jurlico` FROM `link_holding` WHERE `holding` LIKE v_toval)) AND `soft` LIKE v_soft; DELETE FROM `jurlico` WHERE `name` IN (SELECT `holding` FROM `link_holding` WHERE `holding` LIKE v_toval) AND `soft` LIKE v_soft; DELETE FROM `holding` WHERE `name` LIKE v_toval AND `soft` LIKE v_soft; SET @Answer = concat(v_soft, ' удален из списка ПО холдинга ', v_toval, '!'); ELSE SET @Answer = concat(v_toval, ' отсутствует в списке холдингов!'); END IF; END IF; END IF; ELSE SET @Answer = concat(v_soft, ' отсутствует в списке софта!'); END IF; SELECT @Answer; END;
Итого мы получили бэкэнд с такой вот структурой
Что важно в бэкэнде, связка у нас работает при помощи процедур. Их можно оперативно изменить, даже не владея php. Объекты связаны по наименованию, а не по uid, т.к. есть определенный синтаксис этих наименований и их можно сравнить с таблицами в других базах. Uid-ов изначально нигде нет. Таблица параметров софта расширяема и не затрагивает саму структуру дерева.
UPD: процедура, которая парсит дерево в таблицу(выборку нижнего уровня):
CREATE DEFINER = '*****'@'********' PROCEDURE update_soft.proc_select_objectsoft() BEGIN DROP TABLE IF EXISTS ObjectSoftTemp; CREATE TEMPORARY TABLE ObjectSoftTemp (`object` varchar(255),`guid` varchar(255),`soft` varchar(255),`path` varchar(255)); INSERT ObjectSoftTemp (`object`, `guid`, `soft`, `path`) SELECT `link_jurlico`.`object`,`link_object`.`guid`,`holding`.`soft`,`software`.`path` FROM `holding` JOIN `software`,`link_holding`,`link_jurlico`,`link_object` WHERE `software`.`name` LIKE `holding`.`soft` AND `holding`.`name` LIKE `link_holding`.`holding` AND `link_holding`.`jurlico` LIKE `link_jurlico`.`jurlico` AND `link_jurlico`.`object` LIKE `link_object`.`object` ORDER BY `path`; INSERT ObjectSoftTemp (`object`, `guid`, `soft`, `path`) SELECT `link_jurlico`.`object`,`link_object`.`guid`,`jurlico`.`soft`,`software`.`path` FROM `jurlico` JOIN `software`,`link_jurlico`,`link_object` WHERE `software`.`name` LIKE `jurlico`.`soft` AND `jurlico`.`name` LIKE `link_jurlico`.`jurlico` AND `link_jurlico`.`object` LIKE `link_object`.`object` ORDER BY `path`; INSERT ObjectSoftTemp (`object`, `guid`, `soft`, `path`) SELECT `link_jurlico`.`object`,`link_object`.`guid`,`object`.`soft`,`software`.`path` FROM `object` JOIN `software`,`link_jurlico`,`link_object` WHERE `software`.`name` LIKE `object`.`soft` AND `object`.`name` LIKE `link_jurlico`.`object` AND `link_jurlico`.`object` LIKE `link_object`.`object` ORDER BY `path`; SELECT * FROM ObjectSoftTemp ORDER BY `object`, `path`; END