Работа с Oracle 4: Функции



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

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

Прежде чем начинать действовать, необходимо составить план действий, так называемый проект, я бы даже сказал мини-проект. Итак, нам необходимо будет разработать возможность просмотра информации по выполнению (отгрузке) заказа. Это будет выглядеть следующим образом: пользователь встаёт на нужный заказ, нажимает печать отчёта "Выполнение заказа", в котором будет построчно выведена каждая позиция заказа с информацией о том сколько изделий заказано, сколько отправлено и сколько осталось на складе."

Для реализации такой функции необходимо выполнить следующие скрипты (не забываем SQLPLUS):

CREATE OR REPLACE FUNCTION Kolvo (PID_STR IN number)
RETURN integer IS
numrows integer;
kolvo_otgr integer;
BEGIN
SELECT count(*) INTO numrows FROM pos_nakl WHERE pid_str=id_str;
IF numrows > 0 then
SELECT sum(kolvo) INTO kolvo_otgr FROM pos_nakl WHERE pid_str=id_str;
RETURN (kolvo_otgr);
elsif numrows = 0 then
kolvo_otgr:=0;
RETURN (kolvo_otgr);
end IF;
END Kolvo;
/
CREATE OR REPLACE FORCE VIEW SCOTT.ZAKAZ_SVOD
(NOMER, KOLVO, DATA, NAIMEN, CHARACT,
KLIENT, KOLVO_OTGR, ID_STR, KOLVO_OST)
AS
SELECT zakaz.nomer, pos_zakaza.kolvo, zakaz.DATA,
izdelie.naimen, izdelie.charact,klient.naimen AS klient,
kolvo(pos_zakaza.id_str) AS kolvo_otgr, pos_zakaza.id_str,
(pos_zakaza.kolvo-kolvo(pos_zakaza.id_str)) AS kolvo_ost
FROM zakaz, pos_zakaza, izdelie, klient
WHERE (zakaz.id_zak = pos_zakaza.id_zak)
AND (izdelie.id_izd = pos_zakaza.id_izd)
AND (zakaz.id_kl=klient.id_kl);
/

Теперь поподробнее о скриптах. В первом случае создаётся функция Kolvo которая получает в качестве входного параметра код строки заказа - PID_STR in number, здесь in означает что параметр входящий, number - тип параметра. return integer - показывает тип возвращаемого значения. Затем в переменную numrows отбирается количество строк (count), значения кода строки в которых соответсвуют значению параметра PID_STR, это делается для проверки наличия таких строк вообще, а затем выполняется проверка полученного значения переменной - если количество строк > 0 тогда выполняется подсчёт количества (sum(kolvo)) товаров в накладной, это число будет показывать отгруженные товары (kolvo_otgr). Если numrows меньше 0 - тогда kolvo_otgr присваивается 0. Таким образом, выполнением данной процедуры мы получаем информацию о количестве отгруженных товаров вы бранной позиции заказа.

Далее мы создаём представление в котором отбираются информация по заказу, наименование клиента и строки позиций заказа, а также присутствует столбец kolvo_otgr который формируется посредством созданной нами процедуры Kolvo, и предназначен для отображения количества отгруженных изделий.
Таким образом база подготовлена, приступаем к проектированию приложения. Добавляем компонент Query, не забываем давать осмысленные имена, у меня это Zakaz_svod, и добавляем компонент DataSource и связываем с нашим Query. Далее свойство DatabaseName у Query устанавливаем наш DataBase (у меня manuf), а в свойстве SQL у Query пишем следующее:

SELECT *
FROM ZAKAZ_SVOD
WHERE NOMER=:nomer

Здесь мы отбираем все значения из представления ZAKAZ_SVOD в которых номер заказа совпадает со значением параметра nomer который мы будем устанавливать при печати отчёта. Заходим в свойство Params нашего Query, и в свойстве параметра nomer - DataType устанавливаем ftInteger. Далее как обычно заходим в редактор полей Query (двойной клик на компоненте), и добавляем все поля (add all fields).

Теперь необходимо добавить компонент RvQueryConnection с закладки Rave и связать с нашим Query (свойство Query). Настройка компонентов выполнена, осталось связать печать отчёта с событием какого-либо компонента. Я решил это сделать через пункт меню Печать, добавив пункт "Выполнение заказа".

Далее на событие нажатия данного пункта меню прописываем следующий код:

Zakaz_svod.ParamByName('nomer').Value:=ZakazNOMER.Value;
Zakaz_svod.Open;
RVProject1.Open;
RVProject1.ExecuteReport('Report3');
RVProject1.Close;
Zakaz_svod.Close;

Здесь мы задаём параметр для Query значением номера текущего заказа, и выполняем печать нашего будущего отчёта, я написал Report3, так как у меня он по счёту будет третий.
Всё, проектирование приложения закончено, переходим к Rave Reports. Запускаем Rave Reports Designer, заходим в меню File->New report. Смотрим в дереве справа в ветке Report Library созданный отчёт, у меня получился Report3, соответственно и в приложении необходимо прописать имя этого отчёта, что я и сделал заранее.

Ну а далее как обычно, добавляем Region с закладки Report, заходим в пункт меню File->New data object->Direct data view и выбираем наш RvQueryConnection, у меня получился RvQueryConnection5, здесь конечно тоже надо было давать RvQueryConnection осмысленное имя, тогда проще было бы выбирать из большого списка Connection'ов, но во всём виновата человеческая лень.

Затем последовательно добавляем два Band'а, один DataBand и один Band с закладки Report, вот что примерно должно получиться:

Затем рисуем вот такую ерунду:

десь поподробнее остановлюсь на свойствах компонентов (отличных от дефолтных, устанавливаемых по умолчанию):

1. Band2:
BandStyle: GroupHeader, First, NewPage (поставить галки);
ControllerBand: DataBand1;
GroupDataView: DataView6 (связанный с RvQueryConnection'ом добавленым в приложении);
GroupKey: NOMER (группировка по номеру заказа);
2. DataBand1:
BandStyle: Detail, First, NewPage;
DataView: DataView6;
3. Band3:
BandStyle: GroupFooter, First, NewPage;
ControllerBand: DataBand1;
GroupDataView: DataView6 (связанный с RvQueryConnection'ом добавленым в приложении);
GroupKey: NOMER (группировка по номеру заказа);

Остальные компоненты я думаю объяснять не надо, для надписей (шапка) используются компоненты Text с закладки Standart, для отображения полей с данными компоненты DataText с закладки Report, связанные с DataView6 и в свойстве DataField соответствующее поле.
Единственно стоит только отметить компоненты отображающие итоги по количеству, они реализованы с помощью CalcText с закладки Report, у них установлены следующие свойства:

1. Суммарное кол-во в заказе:
Controller: DataBand1;
DataField: KOLVO;
DataView: DataView6;
Initializer: DataText6 (компонент в котором отображаются данные по количеству)
2. Суммарное кол-во отгруженное:
Controller: DataBand1;
DataField: KOLVO_OTGR;
DataView: DataView6;
Initializer: DataText7 (компонент в котором отображаются данные по отгруженному количеству)
3. Суммарное кол-во остаточное:
Controller: DataBand1;
DataField: KOLVO_OST;
DataView: DataView6;
Initializer: DataText8 (компонент в котором отображаются данные по оставшемуся количеству)

Вот вроде и всё, разработка закончена, при нажатии пункта меню Печать->Выполнение заказа видим вот такой отчёт:

При переходе на другой заказ будем видеть соответсвующие данные по заказу и товарам, если конечно сформированы предварительно накладные и указано количество отгружаемой продукции.
Таким образом процедуры и функции позволяют реализовать сложные вычислительные механизмы не обременяя компьютер клиента, так как все расчёты производятся на сервере, в этом преимущество архитектуры клиент/сервер. Вот на сегодня и всё, увидимся вследующий раз, надеюсь.

Written by: Ronin (master_t@inbox.ru)