|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
Всем привет! Вот стало интересно написать процедрку-триггер на табличку. Смысл таков - в одной таблице значения, а в другой сумма. Например: табличка 1 - tab1 id_tab vsego110215320 табличка 2 - tab2 id_tab (autoinc) id_tab1 (ссылка на tab1.id_tab) kol_vo (числа которые добавляются меняются удаляются)11521532104255310635735 Теперь, например мы делаем следующее: Код: plaintext
Код: plaintext
Код: plaintext
Собственно триггер должен выполнить примерно это: procedure my_proc() *1. взять строку на которой стоим, и из нее вытащить id_tab1 чтобы дальше сделать выборку: Код: plaintext
Код: plaintext 1. 2.
endproc Результат должен быть такой: id_tab vsego150 (добавили строчку со значением 40)225 (увеличили на 10)315 (удалили 6-ю строку со значением 5) Вставляю эту процедуру как триггер на upd ins del C удалением понимаю - лажа должна выходить, так как строки уже нет. Только если честно, то получается ерунда... Подскажите плиз, почему? ... |
|||
:
Нравится:
Не нравится:
|
|||
21.04.2009, 21:29 |
|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
кстати, ошибся, с удалением лажи быть не должно, ведь сама строка не удаляется, а всего лишь помечается на удаление, т.е. курсор остается именно на ней. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.04.2009, 16:32 |
|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
Imperous Только если честно, то получается ерунда... Подскажите плиз, почему? Получается ерунда наверно потому что буферизация не учтена. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.04.2009, 17:46 |
|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
Не надо сканировать ту таблицу, модификации в которой и выполняются. Лучше сделайте более простой триггер Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29.
Дело разумеется, вовсе не в буферизации. Точнее, не в той буферизации, которая накладывается через CursorSetProp(). Дело в том, что "по определению" триггер - это "вратарь". Последний контролер, который принимает решения записать-таки сделанные изменения в таблицу или нет. Но, раз данные еще не записаны, то что же вы планируете считывать через запросы? Ведь запрос - это обращение напрямую к таблице-источнику. А в ней внесенных изменений пока еще нет. Они есть только в текущей рабочей области. Вот вам подзапрос по tab2 "фигню" и возвращает. Точнее, он возвращает данные по состоянию ДО модификации. А прямое чтение поля таблицы в текущей рабочей области как раз и вернет значение ПОСЛЕ модификации. Триггера FoxPro обрабатывают по одной записи за раз. Групповая обработка записей невозможна. Поэтому внутри тела триггера всегда находимся на одной записи таблицы, вызвавшей срабатывание триггера. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.04.2009, 23:49 |
|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
ВладимирМ, Когда заменил свой аналогичный триггер: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.
на триггер по схеме ВладимирМ то получил такой Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30.
то он успешно заработал,хотя не могу обьяснить смысл: Код: plaintext 1. 2.
... |
|||
:
Нравится:
Не нравится:
|
|||
24.04.2009, 12:28 |
|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
ВладимирМ, понятно, пасиб :) ... |
|||
:
Нравится:
Не нравится:
|
|||
24.04.2009, 12:34 |
|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
LUCIAN Вообще-то, конечно, в данном случае можно обойтись и без этого анализа. Написав примерно так Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.
Однако я написал тиггер "в общем виде". Т.е. исходя из предположения, что, во-первых, одна и та же функция будет вызываться из всех типов триггеров, предполагая, что для разных типов триггеров потребуется некоторые разные действия. А, во-вторых, чтобы не передавать дополнительный признак, указывающий на то, из какого типа триггера была вызвана данная функция, я сделал анализ, позволяющий это однозначно определить. Анализ производится через оператор CASE по той причине, что данный оператор прерывает свое выполнение в тот момент, когда очередной CASE примет значение .T. Это значит, что если перешли на очередной CASE, то все предыдущие вернули .F. Первой выполняется проверка на удаление. Если функция Deleted() вернула .T., то данная функция была вызвана из триггера на удаление. Вызова из триггера на модификацию не может быть по той причине, что при модификации записей, помеченных как удаленные триггер на модификацию не срабатывает. Игнорируется. Следующая проверка выглядит так Код: plaintext
Раз мы попали на эту проверку, то данную функцию вызвал либо триггер на вставку, либо триггер на модификацию. Триггер на вставку может сработать по двум причинам: 1. При физическом создании новой записи 2. По команде RECALL при снятии метки на удаление Если дали команду Recall, то, очевидно, что OldVal("Deleted()") вернет .T. Ведь до модификации записи эта запись была помечена как удаленная. Однако напомню, что в данный момент запись НЕ помечена как удаленная. Это уже проверили на предыдущем этапе. Если же это физическое создание новой записи, то OldVal() по любому выражению вернет NULL. Вот и получается, что это условие читается примерно так: До модификации был установлен признак удаленной записи, который сейчас сняли ИЛИ это новая запись Это условие может вернуть .F. только и исключительно тогда, когда ДО модификации Deleted()=.F. Т.е. запись существовала и это не есть удаление, поскольку этот факт был проверен еще на первом CASE. Значит, Otherwise - это только и исключительно модификация. ============================= Кроме того, не следует внутри тела триггера обращаться по имени таблицы явно. Вот эта самая конструкция Код: plaintext 1.
потенциально опасна. Может привести к не предсказуемым последствиям. Во-первых, внутри тела триггера, автоматически происходит переход в рабочую область той таблицы, модификация в которой вызвала срабатывание триггера. При завершении триггера, также автоматически, осуществляется возврат в исходную рабочую область. Во-вторых, очевидно, что имя таблицы, в общем случае, может не совпадать с алиасом, используемым в той рабочей области, где таблица была открыта. А это значит, что команда Код: plaintext
разумеется, сделает переключение в нужную рабочую область, однако не факт, что рабочая область с именем "DOKS" - это та область, где и были выполнены модификации. Поэтому, если так уж хочется явно указывать алиас таблицы, то это придется делать через макроподстановки. Примерно так Код: plaintext 1. 2. 3.
Также следует озаботится "уборкой мусора". Точнее, возвращение в то состояние при выходе из триггера, которое было на момент входа в триггер. Закрыть все таблицы, открытые в теле триггера и вернуться в ту рабочую область, в которой были при входе в триггер. Команда Update-SQL автоматически открывает ту таблицу, в которой выполняются модификации. Поэтому, если талица не была открыта до выполнения команды Update-SQL необходимо ее закрыть после выполнения. ... |
|||
:
Нравится:
Не нравится:
|
|||
24.04.2009, 15:52 |
|
процедурка на ins, upd и del
|
|||
---|---|---|---|
#18+
ВладимирМ, Спасибо за подробное объяснение. Мои попытки организовать с помощью триггеров автоматическое формирование текущих остатков материалов на складах были не успешны.Попытаюсь в ближайшее время решить эту проблему с помощью вышеуказанной схемы организации триггера. ... |
|||
:
Нравится:
Не нравится:
|
|||
25.04.2009, 16:09 |
|
|
start [/forum/topic.php?fid=41&fpage=129&tid=1586530]: |
0ms |
get settings: |
12ms |
get forum list: |
12ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
136ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
99ms |
get tp. blocked users: |
2ms |
others: | 333ms |
total: | 615ms |
0 / 0 |