Правильная ссылка на эту страницу
http://az-design.ru/Support/DataBase/DBTree2/2400.shtml

Самое простое применение древовидных структур

Архангельский Андрей

       Как ни странно, но самое простое и очень эффективное применение древовидных структур не имеет древовидного отображения. Так как древовидные структуры применяются в основном в справочниках, то простейший справочник, который имеет всего два уровня — группы и элементы групп. В качестве примера, используем справочник по единицам измерения {Example03}, внешний вид которого показан ниже:


Рис.1-3 Отображение единиц измерения

Построение таблицы

       Описание таблицы и заполнение ее данными приведено в файле DBCreate.doc

Create table UNITCODES (
   UNITID         Integer not null primary key,
   UNITParnt      Integer default 0, 
   UNITCount      Integer default 0,
   UnitCode       Integer not null, /* Код единицы измерения                */
   UnitDecl       AZTITLE,          /* Наименование единицы измерения       */
   UNISmbNat      AZNOVIN,          /* Условное обозначение – национальное  */
   UNISmbInt      AZNOVIN,          /* Условное обозначение – международное */
   UNICodNat      AZNOVIN,          /* Кодовое обозначение – национальное   */
   UNICodInt      AZNOVIN);         /* Кодовое обозначение – международное  */
Commit;
Insert into UnitCodes(UnitID,UnitParnt,UnitCode,UnitDecl) values(0,0,0,'');
Commit;
Alter table UnitCodes add foreign key (UnitParnt)
      references UnitCodes on UPDATE cascade;
Commit;
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl)
               values(0,10000,'Единицы времени');
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl) 
               values(0,20000,'Единицы длины');
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl)
               values(0,30000,'Единицы массы');
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl)
               values(0,40000,'Единицы объема');
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl)
               values(0,50000,'Единицы площади');
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl)
               values(0,60000,'Технические единицы');
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl)
               values(0,70000,'Экономические единицы');
Commit;
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl,UNISmbNat,UNISmbInt,
                      UNICodNat,UNICodInt)
  Select UnitID, 352,'Микросекунда','мкс','','МКС',''
     from UnitCodes where UnitDecl='Единицы времени';
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl,UNISmbNat,UNISmbInt,
                      UNICodNat,UNICodInt)
  Select UnitID, 353,'Миллисекунда','млс','','МЛС',''
     from UnitCodes where UnitDecl='Единицы времени';
Insert into UnitCodes(UnitParnt,UnitCode,UnitDecl,UNISmbNat,UNISmbInt,
                      UNICodNat,UNICodInt)
  Select UnitID, 354,'Секунда','с','s','C','SEС'
     from UnitCodes where UnitDecl='Единицы времени';
. . . .
Commit;

       Заполнение данными происходит сразу после создания таблицы в том же скрипте, который создает БД. В результате получается готовый справочный объект, который может использоваться как в БД, так и в приложении.

Построение интерфейса

       Для построения такого интерфейса нужны две простые функции:
       — при создании формы сформировать список значений в ComboBox,
       — при выборе значения в ComboBox сформировать запрос отображения в DBGrid значений выбранной группы.
       Например, так:

procedure TSDIAppForm.FormCreate(Sender: TObject); {Example03}
Var
   db : String;
   ps : Integer;
begin
   db := ExtractFilePath(Application.ExeName);
   db := ReverseString(db);  Delete(db,1,1);
   ps := Pos('\',db);  Delete(db,1,ps);
   db := ReverseString(db)+'\DB_Tree.fb';
   IBDatabase.DatabaseName := db;
   IBDatabase.Connected := True;
// Выбор групп (родители)
01 qrGroup.Close;   qrGroup.SQL.Clear;
02 qrGroup.SQL.Add('Select UnitDecl,UnitCode from UnitCodes');
03 qrGroup.SQL.Add(' where UnitParnt=0 and UnitID<>0 order by UnitCode');
04 qrGroup.Open;   qrGroup.First;
// Создание списка групп
05 ComboBox.Items.Clear;
06 While not qrGroup.Eof do Begin
07    ComboBox.Items.Add(qrGroup.FieldValues['UnitDecl']);
08    qrGroup.Next;
09 end;
   qrGroup.Close;
   ComboBox.ItemIndex := 0; // Встать на первую позицию
   ComboBoxSelect(Sender);  // Вызвать процедуру отображения таблицы
end;

       Для выбора групп открываем запрос, в котором поле UnitParnt=0 и полученными значениями заполняем список в ComboBox:
       — строки 01-04 формируют запрос всех родителей (UnitParnt=0) и сортирует по коду единицы измерения (order by UnitCode).
       — строки 05-09 проходя в цикле по всему запросу формируют список значений в ComboBox.
       Для отображения в DBGrid значений в группе используем процедуру, которая срабатывает по событию ComboBox.onSelect:

procedure TSDIAppForm.ComboBoxSelect(Sender: TObject); {Example03}
Var
   UnitID : Integer;
begin
01 qrGroup.Close;   qrGroup.SQL.Clear;
02 qrGroup.SQL.Add('Select UnitID from UnitCodes');
03 qrGroup.SQL.Add(' where UnitDecl='''+ComboBox.Text+'''');
04 qrGroup.Open;
05 UnitID := qrGroup.FieldValues['UnitID'];
06 qrGroup.Close;
07 IBTransaction.Active := False;  IBTransaction.Active := True;
08 IBQuery.Close;   IBQuery.SQL.Clear;
09 IBQuery.SQL.Add('Select UNITID,UnitCode,UnitDecl,UniSmbNat,UniSmbInt,');
10 IBQuery.SQL.Add('UniCodNat,UniCodInt from UnitCodes');
11 IBQuery.SQL.Add(' where UnitParnt='+IntToStr(UnitID));
12 IBQuery.SQL.Add(' order by UnitCode');
// Для обеспечения редактирования
// Запрос на удаление
   IBUpdateSQL.DeleteSQL.Clear;
   IBUpdateSQL.DeleteSQL.Add('Delete from UnitCodes');
   IBUpdateSQL.DeleteSQL.Add(' where UnitID = :OLD_UnitID');
// Запрос на вставку
   IBUpdateSQL.InsertSQL.Clear;
   IBUpdateSQL.InsertSQL.Add('Insert into UnitCodes(UnitParnt,UnitCode,');
   IBUpdateSQL.InsertSQL.Add('UnitDecl,UniSmbNat,UniSmbInt,');
   IBUpdateSQL.InsertSQL.Add('UniCodNat,UniCodInt)');
   IBUpdateSQL.InsertSQL.Add(' Select UnitID,:UnitCode,:UnitDecl,:UniSmbNat,');
   IBUpdateSQL.InsertSQL.Add(':UniSmbInt,:UniCodNat,:UniCodInt ');
   IBUpdateSQL.InsertSQL.Add(' from UnitCodes ');
   IBUpdateSQL.InsertSQL.Add(' where UnitDecl='''+ComboBox.Text+'''');
// Запрос на модификацию
   IBUpdateSQL.ModifySQL.Clear;
   IBUpdateSQL.ModifySQL.Add('Update UnitCodes Set');
   IBUpdateSQL.ModifySQL.Add(' UnitCode  = :UnitCode,');
   IBUpdateSQL.ModifySQL.Add(' UnitDecl  = :UnitDecl,');
   IBUpdateSQL.ModifySQL.Add(' UniSmbNat = :UniSmbNat,');
   IBUpdateSQL.ModifySQL.Add(' UniSmbInt = :UniSmbInt,');
   IBUpdateSQL.ModifySQL.Add(' UniCodNat = :UniCodNat,');
   IBUpdateSQL.ModifySQL.Add(' UniCodInt = :UniCodInt');
   IBUpdateSQL.ModifySQL.Add(' Where UnitID = :OLD_UnitID');
// Запрос на удаление
   IBUpdateSQL.DeleteSQL.Clear;
   IBUpdateSQL.DeleteSQL.Add('Delete from UnitCodes');
   IBUpdateSQL.DeleteSQL.Add(' where UnitID = :OLD_UnitID');
// Запрос на обновление
   IBUpdateSQL.RefreshSQL.Clear;
   IBUpdateSQL.RefreshSQL.Add('Select * from UnitCodes');
   IBUpdateSQL.RefreshSQL.Add(' where UNITID = :OLD_UNITID');
   IBQuery.Open;
end;

       Первый запрос в строках 01-06 получает от ComboBox значение выбранной группы и находит по нему ID родителя.
       Второй запрос в строках 08-12 служит для отображений группы в DBGrid.
       Особенно нужно отметить, что для обеспечения редактирования DBGrid на форме нужно разместить компонент IBUpdateSQL, в котором нужно прописать отдельные запросы на каждое действие — Insert, Modify, Delete, Refresh. В принципе особенным является только запрос на вставку нового значения, так как нужно не просто вставить значения из DBGrid, но и найти идентификатор родительской записи.
       При использовании IBObjects эта же процедура становиться много проще:

procedure TSDIAppForm.ComboBoxSelect(Sender: TObject); {Example03IBO}
Var
   UnitID : Integer;
begin
   qrGroup.Close;   qrGroup.SQL.Clear;
   qrGroup.SQL.Add('Select UnitID from UnitCodesэ);
   qrGroup.SQL.Add(' where UnitDecl='''+ComboBox.Text+'''');
   qrGroup.Open;
   UnitID := qrGroup.FieldValues['UnitID'];
   qrGroup.Close;
   qrGrid.Close;   qrGrid.SQL.Clear;
   qrGrid.SQL.Add('Select UNITID,UnitCode,UnitDecl,UniSmbNat,UniSmbInt,');
   qrGrid.SQL.Add('UniCodNat, UniCodInt from UnitCodes');
   qrGrid.SQL.Add(' where UnitParnt='+IntToStr(UnitID));
   qrGrid.SQL.Add(' order by UnitCode');
   qrGrid.SQL.Add(' for update');
   qrGrid.Open;
end;

       Т.е. для обеспечения редактирования запроса его последняя строка должна содержать слова 'for update'.
       Если нужно добавить группу, то она записывается в таблицу с помощью запроса "Insert ..." с полем Parent=0.

ibQuery.Close;  ibQuery.SQL.Clear;
ibQuery.SQL.Add('Insert into TabGroup(Parent,GrpName)');
ibQuery.SQL.Add(' values(0,''Наименование группы 2'')');
ibQuery.ExecSQL;

       Для добавления элемента в определенную группу, используется следующий запрос:

ibQuery.Close;  ibQuery.SQL.Clear;
ibQuery.SQL.Add('Insert into TabGroup(Parent,GrpName)');
ibQuery.SQL.Add(' Select GrpID,''Наименование элемента 23''');
ibQuery.SQL.Add(' from TabGroup);
ibQuery.SQL.Add(' Where GrpName=''Наименование группы 2''');
ibQuery.ExecSQL;

© 01.08.2009, Архангельский А.Г.

<<Пред. Оглавление
Начало раздела
След.>>




Дата последнего изменения:
Thursday, 21-Aug-2014 09:10:44 MSK


Постоянный адрес статьи:
http://az-design.ru/Support/DataBase/DBTree2/2400.shtml