| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Firebird, Interbase > Отображение данных при древовидной структуре |
| Автор: FMA 16.10.2009, 17:03 | ||
| Разрабатываю БД на Firebird 2.1.3, для доступа использую компоненты FibPlus. Используется древовидная структура:
В интерфейсной части программы показывается полученное дерево и данные в виде таб-цы. При перемещении по узлам дерева, показываются данные которые входят конкретно в группу. Суть проблемы состоит в том как лучше организовать обработку показа всех данных, входящих в подгруппы выделенной группы? Одновременно с программой будут работать несколько пользователей. Количество записей будте около 10 тыс. Кто-нибудь сталкивался с такой проблемой? |
| Автор: Gluttton 16.10.2009, 17:35 | ||
Глубина вложености жестко фиксирована и равна единице? В чем же тогда проблема? 1. Пользователь выбирает узел дерева. 2. Клиентское приложение определяет, какому ID_GRD соответствует этот узел. 3. Клиентское приложение вызывает на сервере зарение подготовленную храниму процедуру, которая делает примерно вот это:
Передавая в качестве входного параметра полученный ранее ID_GRD. 4. Клиентское приложение принимает от сервера данные, которые возвращает хранимая процедура. |
| Автор: FMA 16.10.2009, 18:11 |
| Вложенность может быть какой угодно, т.е. у одной группы может быть сколько угодно своих подгрупп, у которых также могут быть подгруппы. С простой выборкой конкретной группы - проблем нет. Самое интересное, как организовать выборку всех данных из всех подгрупп входящих в выбранную группу. |
| Автор: FMA 16.10.2009, 20:01 |
| Не совсем хорошо, т.к. у группы есть свои параметры, а у данных входящих в нее свои. Большой дубляж данных получится. Хотя насчет рекурсионного запроса, думаю не проблема будет и для нынешней структуры написать. Насчет отображения пользователю всех данных - не повесит ли он сетку при быстром переходе с одного узла на другой? Понимаю что идет считывание только видимых в таблице строк. Но тут вопрос вот еще в чем - а если пользователь захочет данные отсортировать, да еще и по нескольким столбцам? Как вариант, конечно можно сразу считать все данные, и обойтись простой фильтрацией данных в дальнейшем. Но мне он как-то не нравится. |
| Автор: Gluttton 16.10.2009, 21:00 | ||||||
ОК. Тогда так:
Не советчик в практических аспектах :( ... Но в голову приходит следующее... Можно сделать несколько хранимых процедур... Первая - отрабатывает быстро и выбирает первые N записей. Вторая - стартует в отдельном потоке и не зависимо от того потребуются ли пользователю другие данные или нет подгружает их в локальный DataSet... Это могло бы быть оправдоно в том случае, если среднестатистического пользователя в большинстве случаев устраивали бы данные по умолчанию (т.е. результат первого запроса). Трафик от этого не уменьшится, но как бы удобнее... наверное... А можно ещё поток второго запроса периодически усыплять... А если например через какое то время t пользователь не "затребовал" других данных, то поток второго запроса можно убить... Это всё при том, что нет критической необходимости предоставлять пользователю обнавленные данные. А если есть, то всё намного сложнее Это так... Пятничные мысли |
| Автор: Gluttton 17.10.2009, 14:22 |
Я это к тому, что не совсем понятно, как при существующей структуре БД реализовать под-узел? Как узнать является ли данный узел корневым, или вложен в какой-нибудь узел? А сделать это можно добавив поле ID parent, в котором бы хранился ID родительского узла или же 0 для корневых узлов... Ещё раз обращу внимание на то, что при такой реализации составление рекурсивного запроса на обход узла является задачей тривиальной... |
| Автор: jsa 18.10.2009, 16:00 |
| FMA, почитай http://www.getinfo.ru/article610.html, там много интересно описывается, я думаю многие вопросы отпадут сами собой |
| Автор: FMA 18.10.2009, 18:19 | ||
А в таблице дерева TABLE GROUP_DATA у меня есть поле ENTRY, в котором и хранится номер "родителя" данной подгруппы. (Надо было, его попроще обозвать. Извиняюсь). Большое спасибо за ссылочку, статья и вправду полезная. |
| Автор: Gluttton 18.10.2009, 18:40 |
| jsa, не совсем согласен... http://forum.vingrad.ru/forum/topic-273313.html похожая тема обсуждалась... Nested Sets необходимы там, гне нет возможности испльзовать рекурсию, а в Firebird такая возможность есть... В Nested Sets удобно делать запросы на выборку, но запросы на вставку или изменение очень ресурсоемкие. Так что это альтернатива, но не панацея |
| Автор: jsa 19.10.2009, 04:48 | ||
наверное я пропустил эту возможность Gluttton, можно пожалуйста поподробнее, как использовать рекурсию в Firebird не согласен с чем? статья - очередной взгляд на проблему хранения деревьев в sql, я никого не принуждал, использовать способы, описанные в статье, и не говорил что это панацея Добавлено через 1 минуту и 19 секунд дык это и была суть этого топика |
| Автор: Deniz 19.10.2009, 06:21 | ||
| сам пока не пользуюсь, но ... Выдержка из http://www.ibase.ru/conf2007/ppt/Firebird.2.1.2007.ru.pdf
|
| Автор: jsa 19.10.2009, 07:49 |
да... действительно пропустил |
| Автор: Gluttton 19.10.2009, 07:56 | ||||
Приведу пример, но позднее... Прошу не обращать внимания Это я наверное сам с собой
Согласен. Как бы да, но я не думаю, что топикстартер при работе с БД ограничится только выборкой, хотя это топикстартеру виднее |
| Автор: Gluttton 19.10.2009, 17:02 | ||||||||||||||||||||||||||||
| UPD... UPD, внес инменения на основании замечаний Deniz по организации каскадного удаления. Deniz, спасибо за поддержку jsa, как и обещал привожу пример работы с древовидными структурами на Firebird с использованием рекурсивных запросов. Создадим БД, которая описывает файловую систему (очень и очень приблизительно Создадим две таблицы: таблицу с директориями D и таблицу с файлами F. следующим образом:
Создадим внешние ключи:
Заполним БД тестовыми данными:
Для первичных ключей реализованы соответсвующие генераторы и триггеры для из заполнения автоинкрементными значениями. Получим примерно следующее: Папки: ![]() Файлы: ![]() Реализуем запрос на выборку всех объектов (как папок так и файлов) расположенных в заданой. Создадим хранимую процедуру с рекурсивным запросом, которая принимает один параметр - папка в которой производиться поиск и возвращает две колонки данных, в первой будем отображать имена объектов, а во второй путь к объекту.
Теперь обратимся к БД с запросом:
В результате выполнения запроса получим следующие данные: ![]() Очевидно, что для того, что бы реализовать выбор только каталогов в указаной папке необходимо из хранимой процедуры удалить один из рекурсивных подзапросов:
Для выбора только файлов в указанной папке и ее подпапках, необходимо заменить код рекурсивного запроса на следующий:
Задача вставки данных решается относительно просто. Для этого необходимо создать хранимую процедуру без использования рекурсии, которая будет принимать например имя родительской папки и, не возвращая никаких параметров, создавать в ней папку (задача вставки файлов решается аналогично):
Теперь можно вставлять данные в БД использую следующий запрос:
Выполним вновь запрос на отображение данных Вот примерно, что должно получиться: ![]() Задача удаления папки (и конечно же всего её содержимого) может быть решена несколькими способами. В обоих случаях процедура принимает одно значение - имя папки, которую необходимо удалить и не возвращает значений. Наиболее простой (предложенный Deniz) способ - это использовать ограничения каскадного удаления. Запрос на создание хранимой процедуры может выглядеть так:
Второй способ, более громоздкий и ресурсоёмкий – это без использования ограничений. Я удалил его из поста, дабы не захламлять последний, но оставил в закомментированном виде в скрипте, который присоединен к посту. Он может быть полезен как шаблон для решения задачи удаления только файлов в выбранной папке и её подпапках (для этого необходимо из приведенного запроса удалить первый оператор delete). Выполним следующий запрос:
И вновь проверим содержимое папки 'media':
Должно получиться примерно следующее: ![]() Выполним запрос на отображени папки 'system':
Получиться: ![]() Реализация запросов на обновление данных всех объектов папки аналогична реализации запроса на выборку данных. Запрос на обновления приведен в прилагаемом скрипте. Работает Вот скрипт по созданию демонстрационной БД. |
| Автор: jsa 20.10.2009, 07:40 |
| Gluttton, отличный пример |
| Автор: Deniz 20.10.2009, 07:47 | ||
Создать ссылочную целостность и on delete cascade и файлов и папок. |
| Автор: Gluttton 20.10.2009, 08:00 | ||
Спасибо!
Хм... Об этом как то и не подумал... Попробую реализовать удаление с использованием ссылочной целосности. Спасибо за рецензирование |
| Автор: jsa 20.10.2009, 08:30 | ||
вот только будет ли работать delete cascade в рекурсии |
| Автор: Deniz 20.10.2009, 08:44 | ||
| будет, проверено опытом. Если использовать пример Gluttton, то запрос
|
| Автор: Gluttton 20.10.2009, 10:34 |
Проверил, будет Deniz, спасибо за подсказку в этой и соседней теме |
| Автор: FMA 26.10.2009, 20:15 |
| Gluttton, спасибо за пример с рекурсией. И всем остальным тоже Большое спасибо за помощь. |