Учебно-методический комплекс дисциплины (опд. Ф. 10) Базы данных (код и название дисциплины по учебному плану специальности)

Вид материалаУчебно-методический комплекс

Содержание


 Задание: Реализуйте подпрограмму выдачи результата произвольного SQL-запроса в таблицу Excel. 
Работа №11. Разработка программы для ввода основных фактов о предметной области
Подобный материал:
1   ...   7   8   9   10   11   12   13   14   15


 Задание:

Реализуйте подпрограмму выдачи результата произвольного SQL-запроса в таблицу Excel.



Работа №9. Просмотр справочников иерархической структуры

Иерархический справочник – это таблица в базе данных, между записями которой устанавливается (рекурсивное) отношение 1:N. Пример иерархического справочника – справочник диагнозов болезней или справочник клиентов торговой фирмы, в частности:


Физические лица 1 уровень иерархии

Местные 2 уровень иерархии

Иванов 3 уровень иерархии

Петров

Иногородние 2 уровень иерархии

Сидоров 3 уровень иерархии



Организации 1 уровень иерархии

ООО 2 уровень иерархии

Гарант-Сервис 3 уровень иерархии

… …

ОАО

КМК

ЗСМК



Прочие




Рисунок 9.1. Справочник иерархической структуры.


Для отражения такой иерархии в структуру таблицы в дополнение к идентификатору записи вводятся еще два поля: Родитель (PARENT), Потомок (CHILD).


Таблица 9.1. Отображение иерархической структуры в реляционной таблице.

ID

PARENT

CHILD

NAME

1

0

1

Физические лица

2

1

2

Местные

3

2

3

Иванов

4

2

4

Петров

5

1

5

Иногородние

6

5

0

Сидоров

7

5

0



9

6

7

ООО

10

7

0

Гарант-Сервис

11

8

0



12

6

9

ОАО

13

9

0

КМК

14

9

0

ЗСМК

15

9

0



16

9

10

Прочие

17

10

11




 Задание:

Разработайте универсальный класс (THCatalog) для просмотра иерархических справочников, и на его основе реализуйте формы просмотра (а в последствии и редактирования) справочников.




Этот класс должен быть основан на модальной форме. Основной интерфейсный элемент в этой форме – компонент класса TDBGrid (по имени Grid). Форма должна создаваться динамически по мере запроса на вывод окна просмотра-редактирования справочника. В элементе Grid должны присутствовать необходимые для просмотра поля справочника (искусственные коды, уникально идентифицирующие запись в справочнике, не должны быть видны по умолчанию, однако следует создать элемент управления, позволяющий сделать их видимыми).

Для просмотра такого справочника следует использовать не TADOTable-компонент, а TADOQuery. Для него следует задать выражение SQL-запроса, которое позволит извлечь записи только одного уровня иерархии. Для этого придется ввести в SQL-запрос параметр, задающий значение поля PARENT, по которому будет осуществляться выборка.


SELECT PARENT, CHILD, NAME FROM CLIENTS WHERE PARENT = :p


В этом выражении :p – обозначение параметра запроса по имени ‘p’.

После вставки этого кода в свойство SQL компонента TADOQuery (договоримся, что его имя – Q), в свойстве Parameters образуется один элемент, соответствующий параметру ‘p’. Необходимо в редакторе параметров TADOQuery определить его тип – в нашем случае Integer.


Для выборки записей самого верхнего уровня иерархии следует задать значение параметра p равным 0. Значение параметра SQL-запроса можно задать следующим образом (компонент TADOQuery по имени Q):


Q.Close;

Q.Parameters.ParamByName(‘p’).Value := 0;

Q.Open;


Для перехода на один уровень иерархии вниз необходимо задать соответствующее значение того же параметра:

Var i:Integerl



i := Q.FieldByName(‘CHILD’).AsInteger; //Определить уровень потомков текущей записи

Q.Close;

Q.Parameters.ParamByName(‘p’).Value:= i; // Перейти на уровень потомков, сделать его текущим

Q.Open;


Для возврата на предыдущий уровень иерархии придется использовать еще один компонент TADOQuery (по имени Q1) (см. таблицу 2.), свойство SQL которого должно содержать код


SELECT PARENT FROM CLIENTS WHERE CHILD = :p1


а параметр ‘p1’ должен будет задаваться в момент, когда нам захочется вернуться на уровень назад (см. Таблица №2):


Q1.Parameters.ParamByName(‘p1’).Value := Q.FieldByName(‘PARENT’).Value;

Q1.Open;

Q.Close;

Q.Parameters.ParamByName(‘p’).Value := Q1.FieldByName(‘PARENT’).AsInteger;

Q1.Close;

Q.Open;


Работа №10. Редактирование справочников иерархической структуры

Имеются 4 случая редактирования справочника, задевающие его иерархическую структуру.


1. Для осуществления ввода новой записи на уже существующем уровне необходимо в поле PARENT новой записи записать общее для всех записей данного уровня значение, а в поле CHILD занести значение 0.


Level := Q.FieldByName(‘PARENT’).AsInteger;

Q2.SQL.Clear;

Q2.SQL.Add(‘INSERT INTO CLIENTS (PARENT, CHILD) VALUES (:p, 0)’);

// Можно задать тип параметра динамически!

Q2.Parameters.ParamByName(‘p’).DataType := ftInteger;

// Задать значение параметра

Q2.Parameters.ParamByName(‘p’).Value := level;

Q2.ExecSQL;


После выполнения этого SQL-запроса, в таблице появиться соответствующая запись, но ее нельзя будет увидеть на форме просмотра-редактирования справочника до тех пор, пока SQL-запрос компонента Q не будет выполнен повторно!


Q.Close;

Q.Open;


2. Для создания записи-потомка для записи, которая еще не имеет детей, необходимо выполнить более сложную работу. Во первых, надо определить значение идентификатора для записей нового уровня (поле PARENT), во вторых это значение занести в поле CHILD родительской записи, в третьих в поле PARENT новой записи-потомка записать это значение, а в поле CHILD занести значение 0:


Q2.SQL.Clear;

Q2.SQL.Add(‘SELECT MAX(PARENT) AS MP FROM CLIENTS’);

Q2.Open;

Level := Q2.FieldByName(‘MP’).AsInteger + 1;

Q2.Close;


Q.Edit;

Q.FieldByName(‘CHILD’).AsInteger := level;

Q.Post;


Q2.SQL.Clear;

Q2.SQL.Add(‘INSERT INTO CLIENTS (PARENT, CHILD) VALUES (:p, 0)’);

Q2.Parameters.ParamByName(‘p’).DataType := ftInteger;

Q2.Parameters.ParamByName(‘p’).Value := level;

Q2.ExecSQL;


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


Try

DM.AdoConnection1.BeginTrans;

Q2.SQL.Clear;

Q2.SQL.Add(‘SELECT MAX(PARENT) AS MP FROM CLIENTS’);

Q2.Open;

Level := Q2.FieldByName(‘MP’).AsInteger + 1;

Q2.Close;


Q.Edit;

Q.FieldByName(‘CHILD’).AsInteger := level;

Q.Post;


Q2.SQL.Clear;

Q2.SQL.Add(‘INSERT INTO CLIENTS (PARENT, CHILD) VALUES (:p, 0)’);

Q2.Parameters.ParamByName(‘p’).DataType := ftInteger;

Q2.Parameters.ParamByName(‘p’).Value := level;

Q2.ExecSQL;


DM.AdoConnection1.CommitTrans;

Except

On e:Exception do

begin

DM.AdoConnection1.RollBack;

ShowMessage(e.Message);

End;

End;


3. Для удаления записи справочника, не последней на текущем уровне, следует просто удалить ее из таблицы


Q2.SQL.Clear;

Q2.SQL.Add(‘DELETE FROM CLIENTS WHERE ID = :t’);

Q2.Parameters.ParamByName(‘t’).DataType := ftInteger;

Q2.Parameters.ParamByName(‘t’).Value := Q.FieldByName(‘ID’).AsInteger;

Q2.ExecSQL;

Q.Close;

Q.Open;


4. Для удаления последней на текущем уровне справочника записи следует выполнить более сложную последовательность действий: во первых удалить запись из таблицы, во вторых записать 0 в поле CHILD родительской записи, в третьих перейти к записям родительского уровня


// Запомнить уровень удаляемой записи

level := Q.FieldByName(‘PARENT’).AsInteger;


// Удалить ее

Q2.SQL.Clear;

Q2.SQL.Add(‘DELETE FROM CLIENTS WHERE ID = :t’);

Q2.Parameters.ParamByName(‘t’).DataType := ftInteger;

Q2.Parameters.ParamByName(‘t’).Value := Q.FieldByName(‘ID’).AsInteger;

Q2.ExecSQL;


// Определить уровень родительской записи

Q2.SQL.Clear;

Q2.SQL.Add(‘SELECT PARENT FROM CLIENTS WHERE CHILD = :t’);

Q2.Parameters.ParamByName(‘t’).DataType := ftInteger;

Q2.Parameters.ParamByName(‘t’).Value := Q.FieldByName(‘ID’).AsInteger;

Q2.Open;

// Запомнить его

newLevel := Q2.FieldByName(‘PARENT’).AsInteger;

// Обнулить ссылку на детей – их больше нет у родительской записи

Q2.SQL.Clear;

Q2.SQL.Add(‘UPDATE CLIENTS SET CHILD = 0 WHERE CHILD = :t’);

Q2.Parameters.ParamByName(‘t’).DataType := ftInteger;

Q2.Parameters.ParamByName(‘t’).Value := level;

Q2.ExecSQL;


// Открыть уровень, который содержит родительскую запись (теперь она уже не родительская!)

Q.Close;

Q.Parameters.ParamByName(‘p’).Value := newLevel;

Q.Open;


Разумеется, весь код следует выполнить в рамках явной транзакции.


Возникает вопрос: а как определить, является ли удаляемая запись последней на текущем уровне? Для этого можно, например, узнать количество записей, возвращенных SQL-запросом, вызвав свойство RecordCount соответсвующего объекта класса TADOQuery:


i := Q.RecordCount;


либо выполнить соответсвующий SQL-запрос с помощью еще одного объекта класса TADOQuery (назовем его qKOL). Такой компонент можно создать динамически, воспользоваться им, а затем уничтожить:


qKol := TADOQuery.Create;

qKol.Connection := DM.DBC;

qKol.SQL.Add(‘SELECT COUNT(*) AS KOL_VO FROM CLIENTS WHERE PARENT=:p ‘);

with qKol.Parameters(‘p’) do begin

DataType := ftInteger;

Value := …

End;

qKol.Open;

i := qKOL.FieldByName(‘KOL_VO).AsInteger;

q.Kol.Close;

FreeAndNil(qKol);


 Задание:

Реализуйте возможность редактирования справочника иерархической структуры в своей программе.




Работа №11. Разработка программы для ввода основных фактов о предметной области

Под фактами предметной области будем понимать то, ради чего собственно и создается приложение. Например, для спорткомплекса таким фактом является то, что клиент Иванов, проживающий по ул. Металлургов 33, 41 и работающий в ОАО НКМК купил абонемент на 8 посещений тренажерного зала по пятницам, в 17.00, заплатив за него 1000 руб.


 Задание:

Реализуйте программу для ввода в базу данных фактов, наблюдаемых в Вашей предметной области. Для этого следует использовать возможность задания свойств с помощью таблиц-справочников. Программа должна поддерживать ввод новых фактов, исправление ошибочно введенных и удаление неверных фактов. Интерфейс программы – на Ваш вкус.