Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Дерево. Определение принадлежности узлов. [Firebird 1.5]


Страницы:   1 2 3

Romkin ©   (2006-08-09 11:53:00) 

Проблема появилась, сижу голову ломаю. Есть у меня БД вопросов, которые разделяются по древовидной структуре разделов, то есть, есть таблица разделов
CREATE TABLE THEME (
   THEME_ID    INTEGER NOT NULL,
   THEME_NAME  VARCHAR(80),
   OWNER_ID    INTEGER,
);
ALTER TABLE THEME
 ADD CONSTRAINT PK_THEME
   PRIMARY KEY (THEME_ID);
alter table THEME
 add constraint FK_THEME_THEME
   foreign key (OWNER_ID)
   references THEME(THEME_ID)
   on delete CASCADE
   on update CASCADE;

В общем, обычное дерево. Есть таблица вопросов:
CREATE TABLE QUESTION (
   QUESTION_ID     INTEGER NOT NULL,
   QUESTION_NAME   VARCHAR(80),
   THEME_ID        INTEGER NOT NULL
);
ALTER TABLE QUESTION ADD CONSTRAINT FK_QUESTION PRIMARY KEY (THEME_ID, QUESTION_ID);

И есть таблица (на самом деле две), связывающая вопрос и тему через билет (утрировал, не особо принципиально):
CREATE TABLE CARDQUESTION (
   CARD_ID      INTEGER NOT NULL,
   SCRIPT_ID    INTEGER NOT NULL,
   QUESTION_ID  INTEGER NOT NULL,
   constraint PK_CARDQUESTION primary key (SCRIPT_ID, CARD_ID, QUESTION_ID)
);
еще есть таблица SCRIPT (THEME_ID, SCRIPT_ID, ...) (показан PK)

То есть, у каждой ветви дерева может быть список вопросов, из которых формируются билеты теста (два поля SCRIPT_ID, CARD_ID - как раз идентификатор билета, SCRIPT - тест). Тест такде принадлежит определенному разделу (THEME_ID). Пока все замечательно.
Все дело в том, что в тест, а именно в CARDQUESTION, можно вставлять вопросы из того раздела, которому принадлежит тест и из любого его потомка. То есть, встав в дереве на какой-либо узел, я вижу все вопросы, которые принадлежат этому узлу, плюс вопросы его потомков. Соответственно, выбрать я тоже могу любой.
Вопрос состоит в том, что мне нужна процедура, которая быстро и оптимально может определить "изолированность" узла раздела (таблица THEME). То есть, мне нужна процедура, которая получает на вход THEME_ID и возвращает RET integer >0 в том случае, когда ни один вопрос из данного раздела и его потомковне используется в тестах его предков.
Кто-нибудь может посоветовать? Есть процедура, выводящая QUESTION_ID для данного THEME_ID и его потомков. Есть процедура, выводящая всех предков для данного THEME_ID. Как бы так поуютнее спарить? join процедур делать не хочется. Предков мало, высота дерева 20 от силы, а вопросов в разделе может быть и под тысячу...


Romkin   (2006-08-09 12:48:00) [41]

Desdechado ©   (09.08.06 12:13) [2] Тест - это таблица SCRIPT, первичный ключ (THEME_ID, SCRIPT_ID). QUESTION - нет, каждый вопрос принадлежит разделу (THEME), соотношение мастер-деталь, поэтому ключ мастера первым стоит. FK я не показывал...
Кажется, я уже нащупал соотношение: взять раздел и всех его потомков, и посмотреть, есть ли в CARD_QUESTION записи, в которых вопросы принадлежат этому множеству, а тесты (SCRIPT) - нет. По идеологии, конечно, в CARDQUESTION должны быть еще два поля, THEME_ID и QUESTION_THEME_ID, но увы, их нет :( Структура старая, меняли...
Почему должны быть? Эта таблица - соединение билета и его вопросов. Билет - деталь теста, тест (SCRIPT) - деталь.  У теста ключ (THEME_ID, SCRIPT_ID), у билета (CARD), следовательно, (THEME_ID, SCRIPT_ID, CARD_ID). У вопроса ключ (THEME_ID, QUESTION_ID). Вот и получается, что соединение CARDQUESTION должно состоять из объединения ключей:
(THEME_ID, SCRIPT_ID, CARD_ID, QUESTION_THEME_ID, QUESTION_ID)
Пожалуй, так и надо сделать...

2zdm © Процедура мне нужна на Firebird, а не на Delphi


zdm   (2006-08-09 12:26:00) [42]

Sel_Node_Tree вычесляется функцией
function FN_Detect_For_Tree(const Sel_Node_Tree: string): string;
var
I: Integer;
begin

I :=  LastDelimiter('.', Sel_Node_Tree);
if (I > 0) and (Sel_Node_Tree[I] = '.') then
  Result := Copy(Sel_Node_Tree, I+1, MaxInt) else
  Result := '';
end      ;


Desdechado   (2006-08-09 12:13:00) [43]

Вот этого не понял
> когда ни один вопрос из данного раздела и его потомков не
> используется в тестах его предков.

И, попутно, что-то уж замудренная структура. Перепутанные сущности и их взаимосвязи:
1. TABLE QUESTION - PK, имхо, должен быть QUESTION_ID, нет FK на THEME_ID
2. так и не понял, что есть "тест" и почему это важное понятие спрятано от глаз.


zdm   (2006-08-09 12:08:00) [44]

реальная тема, я долго с деревьями мучался,,,и в конечном итоге оказалась самая реальная структура----это
id|pid|tree|name
пример
1 0 0 все
2 1 1. Юр.лица
3 2 1.1 ООО "ЗЗЗ"
4 1 2. Физ. Лица
ну и т.д. а на событие OnChange TreeView пишешь запрос "select ... from ... where tree Like '+QuotedStr( Sel_Node_Tree+'%')"


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо