Это может быть очень сложным набором значений, полученным из выражений, со-
единений или агрегатных операций. В хранимой процедуре операция INSERT может разветвляться в предложении ELSE предиката IF (EXISTS (...)), например:
IF EXISTS(SELECT...) THEN
. . .
ELSE
BEGIN
INSERT INTO TABLEA
SELECT
C.PKEY,
SUM (B. AVALUE) ,
AVG(B.BVALUE),
COUNT(DISTINCT C.XYZ)
FROM TABLEB B JOIN TABLEC С
ON B.X = C.Y
WHERE C.Z = 'value'
AND С.PKEY NOT IN(SELECT PKEY FROM TABLEA)
GROUP BY С.PKEY;
END
. . .
Реализация этого в хранимой процедуре:
FOR SELECT
С.PKEY,
SUM(B.AVALUE),
AVG(B.BVALUE),
COUNT(DISTINCT C.XYZ)
FROM TABLEB B JOIN TABLEC С
ON B.X = C.Y
WHERE C.Z = 'value'
AND С.PKEY NOT IN(SELECT PKEY FROM TABLEA)
GROUP BY С.PKEY
INTO :C_KEY, :TOTAL, :B_AVG, :C_COUNT DO
BEGIN
SELECT A.RDB$DBKEY FROM TABLEA A
WHERE A.PKEY = :C_KEY
INTO :DBK;
IF (DBK IS NULL) THEN /* строка не существует */
INSERT INTO TABLEA(PKEY, TOTAL, AVERAGE_B, COUNT_C)
VALUES(:C_KEY, :TOTAL, :B_AVG, :C_COUNT);
ELSE
UPDATE TABLEA SET
TOTAL = TOTAL + :TOTAL,
AVERAGE_B = AVERAGE_B + :B_AVG,
COUNT_C = COUNT_C + :C_COUNT
WHERE A. RDB$DB_KEY = : DBK;
END
По умолчанию областью действия db key является текущая транзакция. Вы можете считать, что он остается правильным во время действия текущей транзакции. Подтверждение или откат транзакции приведет к тому, что значения RDB$DB_KEY станут непредсказуемыми. Если вы используете commitRetaining, контекст транзакции сохраняется, блокируя сборку мусора и, следовательно, предотвращая "переназначение" старого db_key. При этих условиях значения RDB$DB_KEY для любых используемых строк в вашей транзакции сохраняются действительными, пока не произойдет "жесткое" подтверждение или откат.
После жесткого подтверждения или отката другая транзакция может удалить строку, которая была изолирована внутри контекста вашей транзакции и, следовательно, рассматривалась как "существующая" в вашем приложении. Любое значение RDB$DB_KEY теперь может указывать на несуществующую строку. Если у вас достаточно большой интервал между моментом, когда начинается ваша транзакция и когда завершается ваша работа, вы должны проверять, не была ли за это время строка изменена или заблокирована другой транзакцией.
Некоторые интерфейсы приложений, например IB Objects, являются суперинтеллектуальными в плане добавлений и могут подготовить "сегмент" для вновь добавленных строк в клиентских буферах для быстрого обновления списка после подтверждения. Такие возможности важны для производительности при работе в сети. Однако "интеллектуальность", подобная этой, основывается на точных реальных ключах. Поскольку db_key является просто заменителем ключа для набора, наследуемого от предыдущих подтвержденных данных, он не имеет смысла для новой строки - он не доступен при изменениях в клиентском буфере.
Значение длительности действия по умолчанию для RDB$DB_KEY можно изменить во время соединения с базой данных, используя параметр API isc_dpb_dbkey_scope. Некоторые разработки - например, компоненты IB Objects в инструментах окружения Borland Object Pascal - предоставляют его в классе соединения. Однако не рекомендуется расширять область действия db key в высоко интерактивной среде, поскольку это остановит сборку мусора, приводя к нежелательному росту размера файла базы данных и замедлению работы системы вплоть до ее зависания или краха. Не используйте соединения, имеющие область действия для db key, отличающуюся от значения по умолчанию.
RDB$DB_KEY в многотабличных наборах
Все таблицы поддерживают свои собственные 8-байтовые столбцы RDB$DB_KEY. Просмотры и соединения во время выполнения генерируют db key путем конкатенации RDB$DB_KEY из строк исходных таблиц. Если вы используете RDB$DB_KEY в многотабличных наборах, будьте особенно внимательны при задании каждого из них.
RDB$DB_KEY не может быть использован между различными таблицами. Не существует возможности установить отношения зависимости между RDB$DB_KEY двух таблиц, за исключением реентерабельных (ссылающихся на себя) соединений.
Многие из техник, описанных в данной главе, применимы к любым модулям PSQL, которые вы создаете. Далее мы сфокусируем наше внимание на техниках и возможностях языка PSQL, которые вы сможете использовать при написании триггеров, автоматически реагирующих на изменение состояния данных в строке или на добавление новой строки.
ГЛАВА 31. Триггеры.
Триггеры - ключевые элементы среди возможностей, предоставляемых Firebird для централизованной реализации бизнес-правил внутри системы управления базой данных. Триггер является автономным модулем, который выполняется автоматически, когда выполняется запрос, который будет изменять состояние данных в таблице.