:: Архив конференции по VFP до 2005 года
Организовать суммирующий файл ч/з тригера
Иван_С
Автор
Имеется в БД две таблички
1. Движения
№ документа
измерение1 С
измерение2 С
значение1 N
значение2 N
2. Остатки
измерение1 C
измерение2 C
значение1 N
значение2 N
Связь м/ду ними по индексу измерение1+измерение2

Суть проблемы: хочу ч/з тригера организовать автоматическое формирование остатка по измерениям(таблице 2), после любых изменений в таблице 1. Но в тригерах не работают ни SUM ни CALCULATE, т.е. провести пересчет оказывается не реальным.
А отслеживать изменение в таблице 1 и полученную разницу добавлять/отнимать в файле остатков мне кажется неправильным.
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
AnatolyS

Сообщений: 4565
Откуда: Санкт-Петербург
Дата регистрации: 21.01.2002
Примерно так:

* триггер на изменение
function table_1_update
local lcKey, lnЗначение1, lnЗначение2, lnRecNo
if значение1 <> oldval(значение1) or значение2 <> oldval(значение2)
lnRecNo = recno()
lcKey = измерение1 + измерение2
lnЗначение1 = значение1
lnЗначение2 = значение2
select sum(значение1) as значение1, sum(значение2) as значение2 ;
from database!Движения ;
where измерение1 + измерение2 = lcKey and not recno() = lnRecNo ;
into cursor tsum nofilter
update database!Остатки ;
set значение1 = tsum.значение1 + lnЗначение1, значение2 = tsum.значение2 + lnЗначение2 ;
where измерение1 + измерение2 = lcKey
use in tsum
endif
endfunc
* триггер на добавление
function table_1_insert
local lcKey, lnЗначение1, lnЗначение2
lcKey = измерение1 + измерение2
lnЗначение1 = значение1
lnЗначение2 = значение2
select sum(значение1) as значение1, sum(значение2) as значение2 ;
from database!Движения ;
where измерение1 + измерение2 = lcKey;
into cursor tsum nofilter
update database!Остатки ;
set значение1 = tsum.значение1 + lnЗначение1, значение2 = tsum.значение2 + lnЗначение2 ;
where измерение1 + измерение2 = lcKey
use in tsum
endfunc
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi, Иван_С!

Или просто повторно открыть ту-же табличку под другим алиасом и работать с
ней (там можно делать всё - и SUM и COUNT и даже менять данные -
предотвратив конечно тем или иным способом рекурсию триггеров ) - так
поступает RI Builder в создаваемых им триггерах ссылочной целостности.




------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
AnatolyS

Сообщений: 4565
Откуда: Санкт-Петербург
Дата регистрации: 21.01.2002
Если повторно открыть таблицу под другим алиасом в теле триггера, то "новых данных" еще в нем (алиасе) не будет. Как следствие, прийдется в теле триггера учитывать буферные значения - то есть, по сути, выйдет примерно тоже, что я привел выше.
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
Владимир Максимов

Сообщений: 14095
Откуда: Москва
Дата регистрации: 02.09.2000
У Вас не совсем правильное понимание того, когда именно происходит срабатывание триггера. В данном случае вообще не требуется делать выборки.

По условиям задачи имеем:

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

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

Следовательно, триггер Insert/Update/Delete для Таблицы1 будет выглядеть примерно так:

Function Modified_Table1
LOCAL lnOldValue, lnNewValue
LOCAL lcOldGroup, lcNewGroup
* Определяю тип триггера из которого была вызвана данная процедура
LOCAL lcTypeTrigger
DO CASE
CASE Deleted()
lcTypeTrigger="DELETE" && триггер на удаление
IF OldVal("Значение")=0
* Удаление нулевого значения не влияет на сумму
RETURN
ELSE
lnOldValue = OldVal("Значение")
lnNewValue = 0
lcOldGroup = OldVal("Измерение")
lcNewGroup = Измерение && Не имеет значение
ENDIF
CASE NVL(OldVal("Deleted()"),.T.)
lcTypeTrigger="INSERT" && триггер на вставку
IF Значение = 0
* Вставка нулевого значения не влияет на сумму
RETURN
ELSE
lnOldValue = 0
lnNewValue = Значение
lcOldGroup = Измерение && Не имеет значения
lcNewGroup = Измерение
ENDIF
OTHERWISE
lcTypeTrigger="UPDATE" && триггер на модификацию
IF OldVal("Значение") = Значение
* В результате модификации Значение не изменилось
* Т.е. не изменилась и сумма
RETURN
ELSE
lnOldValue = OldVal("Значение")
lnNewValue = Значение
lcOldGroup = OldVal("Измерение")
lcNewGroup = Измерение
ENDIF
ENDCASE
* Открываем таблицу с суммами
USE Таблица2 IN 0 AGAIN ALIAS __TriggerTable2
SELECT __TriggerTable2
* Ищем запись для уменьшения старого значения
LOCATE FOR Измерение = m.lcOldGroup
IF FOUND()
REPLACE Значение WITH Значение - m.lnOldValue
ENDIF
* Ищем запись для увеличения нового значения
LOCATE FOR Измерение = m.lcNewGroup
IF FOUND()
REPLACE Значение WITH Значение + m.lnNewValue
ELSE
INSERT INTO __TriggerTable2 (Измерение, Значение) VALUES (m.lcNewGroup, m.lnNewValue)
ENDIF
* Закрываем таблицу с суммами
USE IN __TriggerTable2
RETURN .T.
ENDFUNC

В принципе, это только общая схема. Здесь надо еще предусмотреть ряд дополнительных проверок (хотя бы на открытие второй таблицы), окружить модификацию транзакцией и предусмотреть внутренний (внутри триггера) обработчик ошибок. Но общая идея именно в этом: вычитаем старое значение и прибавляем новое. Все! Никакого суммирования по таблице!



Отредактировано (01.03.05 10:24)


------------------
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
AnatolyS

Сообщений: 4565
Откуда: Санкт-Петербург
Дата регистрации: 21.01.2002
Владимир, потрудитесь указать место, где у меня "не совсем правильное понимание того, как именно происходит срабатывание триггера".
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
Владимир Максимов

Сообщений: 14095
Откуда: Москва
Дата регистрации: 02.09.2000
Цитата:
Владимир, потрудитесь указать место, где у меня "не совсем правильное понимание того, как именно происходит срабатывание триггера".
А вот эта самая логика:

SELECT SUM(...)

Триггер обрабатывает изменение одной записи. Значит и общая сумма должна измениться только на то значение, на которое измениться в этой записи. Какой тогда смысл в суммировании значений, которые не изменились?

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

Но это не есть задача триггеров. Это задача отдельных служебных процедур. Навешивать это на триггер - это создавать себе дополнительные проблемы.




------------------
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
AnatolyS

Сообщений: 4565
Откуда: Санкт-Петербург
Дата регистрации: 21.01.2002
Владимир, логика может быть какой угодно. Может автор захочет каким-то образом анализировать полученные суммы - вам и мне это не известно. Автор хотел суммирование - он его получил.
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
Иван_С
Автор
Спасибки всем. Остановился на примере Владимира Максимова. Действительно довольно быстро и надежно и сломать никак не удалось из программ.
Поэтому еще вопрос: Какие ошибки и когда могут возникнуть в тригерах? И что надо сделать чтобы ее вызвать?
А то неясно на какие ситуации обработчик ошибок писать
Ratings: 0 negative/0 positive
Re: Организовать суммирующий файл ч/з тригера
Владимир Максимов

Сообщений: 14095
Откуда: Москва
Дата регистрации: 02.09.2000
Цитата:
Поэтому еще вопрос: Какие ошибки и когда могут возникнуть в тригерах? И что надо сделать чтобы ее вызвать?
А то неясно на какие ситуации обработчик ошибок писать
Основные ошибки связаны с моментом открытия таблицы и с моментом модификации данных.

Данный триггер должен:

-) Открыть вторую таблицу - возможна ошибка открытия
-) Сделать запись в эту таблицу - возможна ошибка записи или запрет на модификацию по условим триггеров, правил (RULE), значений по умолчанию (DEFAULT) в этой таблице
-) Если во второй таблице модифицируется больше чем одна запись (кроме значения изменились критерии), то вся модификация обязательна должна быть окружена транзакцией - необходима проверка на уровень вложенности транзакций (не может быть больше 5)

В принципе, в приведенном коде можно сократить количество модификаций. Например, при удалении записи нет смысла искать новое значение. А при создании новой записи нет смысла искать старое значение. Но это зависит от условия задачи.

Вообще, по поводу триггеров почитай здесь

www.foxclub.ru




------------------
Ratings: 0 negative/0 positive


Извините, но у вас нет прав для того, чтобы оставлять сообщения в этом форуме.

On-line: 5 (Гостей: 5)

© 2000-2024 Fox Club 
Яндекс.Метрика