
- •Хранимые процедуры
- •Управление транзакциями
- •Кэширование памяти
- •Обработка исключений
- •Формирование и вывод отчетов
- •Технология ado
- •Установление привилегий доступа к данным
- •Копирование, перенос данных. Восстановление данных
- •Is Required – требование обязательного ввода значения,
- •Создание дистрибутива приложения
Хранимые процедуры
Хранимая процедура представляет собой подпрограмму, расположенную на сервере и вызываемую из приложения клиента. Использование этих объектов увеличивает скорость доступа к БД по следующим причинам:
- вместо текста запроса, который может быть достаточно длинным, серверу передается по сети относительно короткое обращение к хранимой процедуре;
- хранимая процедура, в отличие от запроса, не требует предварительной синтаксической проверки.
Хранимая процедура создается инструкцией:
CREATE PROCEDURE
<Имя процедуры>[(<Список входных параметров>)]
[RETURNS (<Список выходных параметров>)]
AS <Тело процедуры>
После имени процедуры идет необязательный список входных параметров, с помощью которых из приложения в процедуру передаются исходные данные. С помощью выходных параметров в приложения передаются результаты выполнения процедуры.
Тело процедуры состоит из двух частей – описательной и исполнительной. В описательной части объявляются переменные, используемые внутри процедуры. Эти переменные являются локальными и по окончании работы процедуры теряют свои значения. В исполнительной части (между BEGIN и END) располагаются инструкции, выполняющие необходимые действия.
[<Объявление переменных>]
BEGIN
<Инструкция>
…
[<Инструкция>]
END
Удаление процедуры выполняется командой:
DROP PROCEDURE <Имя процедуры>
Изменение процедуры выполняется командой:
ALTER PROCEDURE
Виды хранимых процедур
По числу строк, возвращаемых в качестве результата, можно выделить следующие виды хранимых процедур:
- возвращает одну строку – процедура действия,
- возвращает несколько строк – процедура выбора.
Примеры создания процедур:
Инструкция выбора записи отбирает несколько строк, но возвращает только одну:
CREATE PROCEDURE pSalary //(желательно называть процедуру с префикса р)
RETURNS (opSum FLOAT, opAvg FLOAT) // (для выходных параметров префикс ор)
AS
BEGIN
SELECT SUM (Salary), AVG (Salary)
FROM Personnel
INTO : opSum, : opAvg;
END
Создается хранимая процедура, в которой для сотрудников организации (таблица Personnel) подсчитывается общая сумма зарплаты и средняя зарплата. Полученные значения присваиваются выходным параметрам opSum и opAvg, которые возвращают полученные значения в вызывающую программу. Входных параметров у процедуры нет.
Инструкция, возвращающая набор данных:
CREATE PROCEDURE pSalary2 (ipSalaryMin FLOAT, ipSalaryMax FLOAT) //(префикс ip для
входных параметров)
RETURNS (opName VARCHAR(20), opSalary FLOAT)
AS
BEGIN
FOR SELECT Name, Salary
FROM Personnel
WHERE Salary >= : ipSalaryMin
AND Salary <= : ipSalaryMax
INTO : opName, : opSalary
DO SUSPEND; // (инструкция используется для возврата в приложение
набора данных)
END
Создается хранимая процедура pSalary2, которая возвращает набор данных. Совокупность записей этого набора образуют записи, соответствующие сотрудникам организации, у которых оклад принадлежит заданному диапазону. Границы диапазона определяют входные параметры ipSalaryMin и ipSalaryMax. Набор данных содержит столбцы Name и Salary.
Вызов хранимой процедуры выбора
В приложении хранимая процедура выбора вызывается с помощью набора данных Query, для чего используется его свойство SQL.
Пример
procedure TForm.Button1Click (Sender: TObject);
begin
Query1.Close;
Query1.SQL.Clear;
Query1.SQL.Add ('SELECT * FROM pSalary2 (2000, 3000)');
Query1.Open;
end;
Пример динамического запроса
Query1.SQL.Add ('SELECT * FROM pSalary2 (' + Edit1.Text + ',' + Edit2.Text + ')');
Вызов хранимой процедуры действия
Процедуру можно выполнить в программе IBConsole.
Для вызова хранимой процедуры действия из приложения предназначен компонент StoredProc.
Свойства компонента:
StoredProcName – имя вызываемой хранимой процедуры;
Params – массив параметров компонента StoredProc;
ParamBindMode – определяет, каким образом устанавливается соответствие между параметрами компонента StoredProc и параметрами процедуры:
- pbByName – устанавливается соответствие по именам;
- pbByNumber – соответствие по номерам – первый параметр компонента соотносится с первым параметром процедуры.
Методы компонента:
Prepare – подготавливает хранимую процедуру к выполнению путем связывания параметров компонента и параметров процедуры;
ExecProc – выполняет процедуру.
Пример:
procedure TForm.Button1Click (Sender: TObject);
begin
StoredProc1. StoredProcName := 'pSalary';
StoredProc1. Prepare;
StoredProc1. ExecProc;
Edit1.Text := StoredProc1.ParamByName ('opSum').Value;
Edit2.Text := StoredProc1.ParamByName ('opAvg').Value;
end;
Вызывается процедура pSalary. Ее результаты - значения выходных параметров opSum и opAvg – выводятся в компонентах Edit1 и Edit2.
Создание генераторов
Генератор – это хранящаяся в БД программа, выдающая при каждом обращении к ней уникальное число.
Создание генератора:
CREATE GENERATOR <Имя генератора>
Начальное значение задается инструкцией:
SET GENERATOR <Имя генератора> TO <Начальное значение (целое число)>
Пример:
CREATE GENERATOR GenStore
SET GENERATOR GenStore TO 1
Обращение к созданному генератору выполняется с помощью функции
GEN_ID (<Имя генератора>, <Шаг>)
Создание триггеров
Триггер – это процедура, которая находится на сервере БД и вызывается автоматически при модификации записей БД, т.е. при изменении столбцов или при их удалении и добавлении. В отличие от хранимых процедур, триггеры нельзя вызывать из приложения клиента, а также передавать им параметры и получать от них результаты.
Создание триггера:
CREATE TRIGGER <> FOR <>
[ACTIVE | INACTIVE]
{BEFORE | AFTER}
{UPDATE | INSERT | DELETE}
[POSITION <Число>]
AS <Тело триггера>
Описатели ACTIVE | INACTIVE определяют активность триггера сразу после его создания. По умолчанию действует ACTIVE.
Описатели BEFORE | AFTER задают момент начала выполнения триггера до или после наступления соответствующего события, связанного с изменением записей.
Описатели UPDATE | INSERT | DELETE определяют, при наступлении какого события вызывается триггер – при редактировании, добавлении или удалении записей.
Для одного события можно создать несколько триггеров, каждый из которых будет автоматически выполнен (если находится в активном состоянии). При наличии нескольких триггеров порядок их вызова (выполнения) определяет число, указанное в операнде POSITION. Триггеры выполняются в порядке возрастания этих чисел.
Удаление триггера:
DROP TRIGGER <Имя триггера>
Изменение триггера:
ALTER TRIGGER
Для доступа к значениям столбца используются инструкции формата:
OLD.<Имя столбца> - обращается к старому (до внесения изменений) значению столбца,
NEW.<Имя столбца> - обращается к новому (после внесения изменений) значению столбца.
Пример:
Создание триггера для занесения в ключевой столбец уникальных значений
CREATE TABLE Store
(S_Code INTEGER NOT NULL ,
…
PRIMARY KEY (S_Code));
CREATE GENERATOR GenStore
SET GENERATOR GenStore TO 1
CREATE TRIGGER CodeStore FOR Store
ACTIVE
BEFORE INSERT
AS
BEGIN
NEW.S_Code = GEN_ID (GenStore, 1);
END
При добавлении к таблице Store новой записи ключевому столбцу S_Code этой записи автоматически присваивается уникальное значение. Это обеспечивается обращением GEN_ID к генератору GenStore.
Пример:
Реализация каскадного удаления записей с участием триггера
CREATE TABLE Store
(S_Code INTEGER NOT NULL ,
…
PRIMARY KEY (S_Code));
CREATE TABLE Cards
(C_Code INTEGER NOT NULL,
C_Code2 INTEGER NOT NULL,
…
PRIMARY KEY (C_Code));
CREATE TRIGGER DeleteStore FOR Store
ACTIVE
AFTER DELETE
AS
BEGIN
DELETE FROM Cards WHERE Store.S_Code = Cards.C_Code2;
После удаления записи в таблице Store буду автоматически удалены все соответствующие записи в таблице Cards.
Замечание: для таблиц не должны действовать ограничения ссылочной целостности, заданные на физическом уровне.
Пример:
Обновление столбцов связи (ключевых столбцов) связанных таблиц, заключающееся в том, что при изменении значения столбца связи главной таблицы соответственно изменяются значения столбца связи всех связанных записей подчиненной таблицы.
CREATE TRIGGER ChangeStore FOR Store
ACTIVE
BEFORE UPDATE
AS
BEGIN
IF (OLD.S_Code <> NEW.S_Code)
THEN UPDATE Cards
SET C_Code2 = NEW.S_Code
WHERE C_Code2 = OLD.S_Code;
END
При изменении столбца S_Code, используемого для связи главной таблицы Store с подчиненной таблицей Cards, автоматически изменяются значения столбца связи C_Code2 соответствующих записей подчиненной таблицы.
Чтобы столбец главной таблицы можно было редактировать, по нему не должен быть создан ключ.
Навигационный доступ к данным с помощью механизма BDE
Навигация по набору данных
Навигация по набору данных заключается в управлении указателем текущей записи (курсором). Этот указатель определяет запись, с которой будут выполняться такие операции, как редактирование или удаление.
Перемещение по записям
Для перемещения указателя текущей записи в наборе данных используются следующие методы:
First – на первую запись,
Next – на следующую запись,
Last – на последнюю запись,
Prior – на предыдущую запись,
MoveBy (Distance: Integer) – на число записей, определяемое параметром Distance.
Пример:
procedure TForm.Button3Click (Sender: TObject);
var s: real;
n: integer;
begin
s:= 0;
Table1.First;
for n:= 1 to Table1.RecordCount do begin
s:= s + Table1.FieldByName ('Salary').AsFloat;
Table1.Next;
end;
Label2.Caption:=FloatToStr (s);
end;
В приведенной процедуре перебираются все записи набора данных Table1, при этом в переменной s накапливается сумма значений, содержащихся в поле Salary. Перебор записей осуществляется с помощью метода Next, вызываемого в цикле. Предварительно с помощью метода First указатель устанавливается на первую запись. После выполнения кода указатель будет установлен на последнюю запись.
Фильтрация записей
Фильтрация – это задание ограничений для записей, отбираемых в набор данных.
В Delphi можно выполнить фильтрацию:
- по выражению,
- по диапазону.
При включении фильтрация действует в дополнение к другим ограничениям, например, SQL-запросу компонента Query.
Фильтрация по выражению
При использовании фильтрации по выражению набор данных ограничивается записями, удовлетворяющими выражению фильтра, задающему условия отбора записей. В связи с тем, что в процессе отбора просматриваются все записи таблицы, фильтрация по выражению эффективна при небольшом количестве записей.
Для задания выражения фильтра используется свойство Filter типа String.
Если имя поля содержит пробелы, то его заключают в квадратные скобки, в противном случае квадратные скобки необязательны. Имена переменных в выражении фильтра использовать нельзя.
Пример:
Salary <= 2000
Отбор всех записей, для которых значение поля оклада (Salary) не превышает 2000.
Post = 'Лаборант' OR Post = 'Инженер'
Отбор записей, поле должности (Post) которых содержит значение Лаборант или Инженер.
Для активизации и деактивизации фильтра применяется свойство Filtered типа Boolean.
Параметры фильтрации задаются с помощью свойства FilterOptions:
- foCaseInsensitive – регистр букв не учитывается;
- foNoPartialCompare – выполняется проверка на полное соответствие содержимого поля и значения, заданного для поиска. При задании условия отбора, например, В* следует это значение свойства отключать.
Фильтрация по диапазону
При фильтрации по диапазону в набор данных включаются все записи, значения полей которых попадают в заданный диапазон. Такая фильтрация применяется к наборам данных Table.
Достоинством данной фильтрации является высокая скорость обработки записей. В отличие фильтрации по выражению, когда последовательно просматриваются все записи таблицы, фильтрация по диапазону ведется индексно-последовательным методом, поэтому этот способ фильтрации применим только для индексированных полей.
Поиск записей
Поиск в наборах данных
Для поиска записей по полям служат методы Locate и Lookup, причем поля могут быть неиндексированными.
Функция Locate ищет запись с заданными значениями полей. Locate (const KeyFields: String; const KeyValues: Variant; Options: TLocateOptions).
Параметр KeyFields задает список полей, по которым ведется поиск. Поля разделяются точкой с запятой.
Параметр KeyValues указывает значения полей для поиска.
Параметр Options позволяет задать комбинации следующих значений:
- loCaseInsensitive – регистр букв не учитывается,
- loPartialKey –допускается частичное совпадение значений.
Пример поиска по одному полю:
Table1.Locate ('Number', 123, [])
Поиск выполняется по полю Number и ищется первая запись, для которой значением этого поля является число 123. Все параметры поиска отключены.
При поиске по нескольким полям используется функция VarArrayOf.
Пример поиска по нескольким полям:
Table1.Locate ('Name; Post;' , VarArrayOf (['П', 'Инженер']), [loCaseInsensitive, loPartialKey])
Поиск выполняется по полям Name и Post, ищется первая запись, для которой значение фамилии начинается с буквы п, а значение должности содержит строку инженер. Регистр букв значения не имеет.
Для поиска в наборе данных используется также метод Lookup. Данная функция осуществляет поиск записи, удовлетворяющей определенным условиям, но, в отличие от метода Locate, не перемещает указатель текущей записи на найденную запись, а считывает информацию из полей записи. Еще одно различие между двумя методами заключается в том, что метод Lookup осуществляет поиск на точное соответствие значений для поиска и значений в полях записей с учетом регистра букв.
Поиск по индексным полям
Для набора данных Table имеются методы, позволяющие вести поиск записей только по индексным полям. Перед вызовом любого из этих методов следует установить в качестве текущего индекс, построенный по используемым для поиска полям. Методы поиска по индексным полям делятся на две группы:
- предназначенные для поиска на точное соответствие – FindKey, SetKey, EditKey, GotoKey,
- допускающие только частичное совпадение – FindNearest, SetNearest, EditNearest, GotoNearest.
Пример поиска на точно соответствие:
procedure TForm1.btnFindClick (Sender: TObject);
begin
Table1.IndexFieldNames := 'City';
Table1.SetKey;
Table1.FieldByName ('City').AsString := edtFindCity.Text;
if not Table1.GotoKey
then ShowMessage ('Запись не найдена!');
end;
Приведенная процедура обработки события нажатия кнопки выполняет точный поиск записей по полю города (City).
Сортировка набора данных
Сортировка набора данных Table выполняется автоматически по текущему индексу. При смене индекса происходит автоматическое переупорядочивание записей.
Задать текущий индекс, по которому выполняется сортировка можно с помощью свойств IndexName или IndexFieldNames. Эти свойства являются взаимоисключающими, и установка значения одного из них приводит к автоматической очистке значения другого. В качестве значения свойства IndexName указывается имя индекса, установленное при его создании. При использовании свойства IndexFieldNames указываются имена полей, образующих соответствующий индекс.
Управление направлением сортировки осуществляется с помощью параметра ixDescending текущего индекса.