Как работать с Trigger-ами? | |
---|---|
ZenTigra Автор Сообщений: 514 Дата регистрации: 03.12.2004 |
В свое время форумчане помогли мне избавиться от ON KEY LABEL , а также помогли разобраться с буферизацией.
Много пришлось переделать в программе, но я довольный результатом, большое Вам за это спасибо. Теперь хочу разобраться с Триггерами. Опишу маленьким примером ту задачу, которую хочу решить (до примера прошу не придираться, все очень упрощенно). Есть две таблицы table1 и table2 Структура table1 key - поле ключа suma - сумма по полям table2 Структура table2 key - поле ключа для связи с table1 suma2 – любые цифры Необходимо чтобы при изменении поля suma2 в table2 происходило автоматическое изменения значения поля suma в table1 Вот на подобии, этого. table1 key suma a1 100 a2 200 table2 key suma2 a1 50 a1 20 a1 30 a2 200 Сейчас вся логика обработки находиться в программе, но иногда случаются потеря целостности данных, когда поле suma не соответствует полю suma2. Думаю что это происходит из-за того, что поле suma2 изменяться из многих мест программы, и есть вероятность ошибки в коде. Вот я и хочу собрать этот код в одном месте (в хранимой процедуре БД), чтоб избавиться от этих ошибок. Вопрос в логике, как это правильно делать. Думаю, в форме где редактируется поле table2 при нажатии на кнопку «записать изменения» сделать код блокировки поля в table1, при успешной блокировке, произойдет сохранения записи, и автоматически выполниться триггер. Вот только хочется обойти подводные камни этой процедуры. Еще вопрос, не относящейся к triggers, но относящийся к этой задаче. Как правильней суммировать поле suma, брать предыдущее значение (в table1) и добавлять (отнимать) новое, или каждый раз суммировать поле suma2 в table2. Записи в table2 очень часто добавляются (изменяются) (приблизительно 500-1000 записей в день). Количество записей в table2 ~300000 PS.В вдогонку, еще одна проблемка. Имя таблицы в программе не совпадает с алиасом. Как с этим работать в хранимой процедуре, обращаться к таблице нужно по ее имени или по алиасу. Исправлено 3 раз(а). Последнее : ZenTigra, 08.04.20 09:15 |
Re: Как работать с Trigger-ами? | |
---|---|
ZenTigra Автор Сообщений: 514 Дата регистрации: 03.12.2004 |
Еще одно проблема.
Поле suma - не должно быть нулевым, и если пользователь набрал a1 -120 (то есть поле suma будет -20) то как отменить сохранение запись? Как реализуется защита при СОХРАНЕНИИ на ввод неправильных данных. (Пожалуйста не советуйте делать проверку до момента сохранения, я хочу еще в хранимую процедуру засунуть проверку на ошибки ввода, или в триггерах это делать НЕЛЬЗЯ) Исправлено 2 раз(а). Последнее : ZenTigra, 08.04.20 09:26 |
Re: Как работать с Trigger-ами? | |
---|---|
of63 Сообщений: 25161 Откуда: Н.Новгород Дата регистрации: 13.02.2008 |
> потеря целостности данных, когда поле suma не соответствует полю suma2.
а может структуру хранения данных переделать атк, чтобы SUMMA была записана в одной табличке? Тогда вопрос "потери целостности" не возникнет... |
Re: Как работать с Trigger-ами? | |
---|---|
ssa Сообщений: 12999 Откуда: Москва Дата регистрации: 23.03.2005 |
Ага, чтоб в случае наличия ошибки в этом поле так её и сохранять, не дай бох убежит... Цитата:Жуть, и как люди с бОльшими на порядки объемами работают... Цитата:Индексы, как утверждают некоторые, нужны ведь только для сортировки. Цитата:И много вы, сударь, видели в БАЗЕ алиасов? Тем более, что в ПРОГРАММЕ одна и та же таблица может быть открыта под несколькими алиасами? А о том, что база и её ХП живут и БЕЗ приложения? О каком алаиасе может идти речь при отсутствии приложения? ------------------ Лень - это неосознанная мудрость. |
Re: Как работать с Trigger-ами? | |
---|---|
ssa Сообщений: 12999 Откуда: Москва Дата регистрации: 23.03.2005 |
Хотеть не вредно, но о какой проверке какого ввода может идти речь при отсутствии приложения с этим самым вводом? ------------------ Лень - это неосознанная мудрость. |
Re: Как работать с Trigger-ами? | |
---|---|
pasha_usue Сообщений: 3647 Откуда: Е-бург Дата регистрации: 06.10.2006 |
При таких исходных данных лучше всего перевести базу данных на SQL. Куда угодно, хоть MS, хоть PG, хоть MY. И уже там осваивать триггеры. Или не осваивать. Не так уж много записей, что б денормализовывать таблицу.
|
Re: Как работать с Trigger-ами? | |
---|---|
PaulWist Сообщений: 14601 Дата регистрации: 01.04.2004 |
1. Подводные камни forum.foxclub.ru можно прочесть весь тред (там правда про II билдер). 2. Триггер необходимо писать не для одной записи, а для множества.
Каждый раз суммировать. Нативные таблицы фокса и триггеры не самые надёжные обьекты БД, лучше посмотреть на взрослые СУБД (бесплатные версии поддерживают БД до 10Г)
Посмотри по ссылке как реализуется в RI ------------------ Есть многое на свете, друг Горацио... Что и не снилось нашим мудрецам. (В.Шекспир Гамлет) |
Re: Как работать с Trigger-ами? | |
---|---|
PaulWist Сообщений: 14601 Дата регистрации: 01.04.2004 |
Надо использовать правило поля (хотя - это зло, лучше триггер), например
------------------ Есть многое на свете, друг Горацио... Что и не снилось нашим мудрецам. (В.Шекспир Гамлет) |
Re: Как работать с Trigger-ами? | |
---|---|
ZenTigra Автор Сообщений: 514 Дата регистрации: 03.12.2004 |
Большое спасибо, почитаю. Сразу все ломать не хочется, а нужно от чего то отталкиваться |
Re: Как работать с Trigger-ами? | |
---|---|
AndyNigmatec Сообщений: 1552 Откуда: Волгоград Дата регистрации: 28.06.2015 |
... почему до 10? Вполне хорошо себя чуЙствуют и бОльшие ))) Правда более 80-100 уже как-то некомфортно ими ворочать без нормального железа. |
Re: Как работать с Trigger-ами? | |
---|---|
pasha_usue Сообщений: 3647 Откуда: Е-бург Дата регистрации: 06.10.2006 |
Это ограничение MSSQL Express. Для Oracle XE вроде 12гб. |
Re: Как работать с Trigger-ами? | |
---|---|
leonid Сообщений: 3202 Откуда: Рига Дата регистрации: 03.02.2006 |
|
Re: Как работать с Trigger-ами? | |
---|---|
pasha_usue Сообщений: 3647 Откуда: Е-бург Дата регистрации: 06.10.2006 |
Ну... За что я и люблю постгрес. Функционал почти оракловский, и ограничений по-сути нет. |
Re: Как работать с Trigger-ами? | |
---|---|
leonid Сообщений: 3202 Откуда: Рига Дата регистрации: 03.02.2006 |
Ну, все-таки не дотягивает. Хинтов нет, статистики нет. |
Re: Как работать с Trigger-ами? | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Вопросы поддержания согласованности денормализованных данных через триггера не лучшим образом решаются... Тем более что из приведенной информации вообще не очевидно что данные необходимо денормализовывать. Может быть для начала просто провести оптимизацию - ускорить выборки для которых необходимы эти самые "суммы по коду"? Тем более что защитить от "неправильного" изменения "автоматически вычисляемое триггером поле" ты всё равно не сможешь... Хранимая процедура и триггер это совершенно не связанные друг с другом вещи. Да, можно написать ХП которая будет синхронно менять данные в 2 (и более) таблицах, и работать с этими таблицами исключительно при помощи этих самых ХП - НО в фоксе нет способов запретить программе обращаться к таблице напрямую - точнее эти способы будут крайне ненадёжными, и по сути кривыми. Да и обойти их всегда можно будет без особого труда. А вот найти в программе все места где так или иначе меняются "напрямую" данные в таблице и заменить там эту прямую работу на работу через ХП - не самая простая и лёгкая работа. Какая-то ересь. Какое отношение блокировка из кода программы имеет к триггерам? Триггер выполняется автоматически, при любой попутке изменения данных в таблице - неважно заблокирована там запись вручную или нет, открыта "снаружи" транзакция или нет, производится модификация данных командой (UPDATE/REPLACE/INSERT/DELETE) или банально в BROWSE окне поменяют значение в поле. Наверное для начала следует вдумчиво почитать что такое триггера, как они работают, а потом раз 5-10 изучить код триггеров и вспомогательных ХП, которые генерирует фоксовый "мастер ссылочной целостности" aka RI Builder. Лучше изучать его как раз на самых примитивных и простых примерах - потому что для реальных таблиц он (сгенерированный код) может оказаться ну очень уж массивным по объёму. Этот вопрос имеет самое прямое отношение к тому из триггера будет это исполняться или нет, и будет ли находится таблица в одном из режимов буферизации или нет. Поскольку для "просто кода" банально негде будет взять "предыдущее значение из поля" - без чего невозможно считать разницу и её уже "добавлять/отнимать" к полю хранящему сумму. А с другой стороны, изнутри триггера не так то и просто обращаться к той же самой таблице для которой произошло срабатывание триггера... Поэтому в отрыве от вопроса ГДЕ этот код будет написан, и в КАКОМ СОСТОЯНИИ будут находится обе таблицы (буферизация, блокировки, в т.ч. неявные которые будут иметь место внутри тела триггера) - невозможно дать ответ. В абстрактной ХП можно просто обращаться к текущей таблице (текущей рабочей области, алиас которой можно получить при помощи ALIAS или номер рабочей области при помощи SELECT() ), а вторую таблицу специально открывать под новым алиасом в новой рабочей области - можно даже закрывать её сразу после внечения необходимых изменений. В триггере ещё добавляется немного возни и ограничений - но в целом после изучения кода триггеров генерируемых RI builder-ом это должно быть примерно понятно. Если триггер возвращает .F. то фокс отменяет модификацию вызвавшую срабатывание триггера, и генерирует ошибку, которую можно поймать и обработать штатным образом. Другое дело что у тебя явно будут сложности в реализации логики "согласования" поля суммы с суммой полей второй таблицы. Потому ещё раз - подумай о том настолько ли необходима в данном случае денормализация, и не проще ли просто всегда когда необходимо считать эту самую сумму по полям одной таблицы. ------------------ WBR, Igor Исправлено 1 раз(а). Последнее : Igor Korolyov, 08.04.20 23:06 |
Re: Как работать с Trigger-ами? | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
О той, которая реализуется триггерами и правилами проверки (field/record validation rules), и которые работают совершенно независимо от приложения, и даже безо всяких приложений, тупо при открытии таблицы в IDE фокса и попытке чего-то там поменять в BROWSE окне. Вопрос лишь в том какие именно проверки имеет смысл реализовывать на уровне БД (тем более фоксовой, где любую "защиту" можно обойти буквально за минуту). И в том, не проще ли банально нормализовать структуру хранения, чтобы не возникало надобности в некоторых "проверках" - типа того что сумма в таблице "остатков" соответствует данным в таблицах "движения". В фоксе такой возможности нет. Фоксовые триггера всегда работают с изменением ровно одной записи (если была исполнена команда меняющая 100500 записей, то просто триггер сработает 100500 раз). В данном случае правило поля не годится, т.к. речь идёт о правиле "сумма по полю amount для всех записей с определённым code должна быть больше нуля". Правило поля применяют для проверок корректности данных только в одном поле одной записи, правило записи - для проверки коррекности затрагивающей разные поля одной записи, а когда речь заходит о группе записей, или записях из другой таблицы (классический пример referential integrity) то это уже работа для триггера. ------------------ WBR, Igor |
Re: Как работать с Trigger-ами? | |
---|---|
Владимир Максимов Сообщений: 14095 Откуда: Москва Дата регистрации: 02.09.2000 |
"Перевожу" постановку задачи
Есть документ, состоящий из шапки и строк. Надо чтобы в шапке отображалась сумма строк. Для этого при изменении суммы в одной строке автоматически это изменение надо добавить в итоговую сумму в шапке По особенностям использования триггера в FoxPro можно почитать здесь Триггер Применительно к данной задаче 1. Внутри тела триггера автоматически окажешься в рабочей области изменяемой "строки". Как следствие, прямо в ней можно использовать OldVal(), чтобы получить значение до изменения. И далее получаешь разницу с текущим значением. 2. Следовательно, остается только найти запись "шапки" и прибавить к итоговой сумме найденную разницу Вопрос в том, как именно организовать это "прибавление" Для текущей строки новую рабочую область открывать не надо. Мы в ней и так находимся. А вот для таблицы "шапки" внутри тела триггера надо именно что открыть новую рабочую область. Если "шапка" уже открыта вне триггера все равно нельзя использовать эту рабочую область. Надо открывать новую Поскольку у нас есть еще дополнительное условие, что итоговая сумма в шапке не должна получиться отрицательной, то нельзя использовать Update-SQL. Тут надо будет сделать банальный поиск через seek+if+replace Т.е. открываем рабочую область шапки, через seek находим запись, проверяем, что после прибавления разницы сумма останется положительной. Если "Да", то вносим изменения и триггер возвращает .T., если "Нет", то триггер возвращает .F. и все изменения откатываются Проверка внутри триггера - это не ДО сохранения. Это именно что "в процессе" сохранения -------------------------- Дополнительные вопросы 1. Рассчитывать сумму в шапке заново по всем строкам или только на разницу? На момент выполнения триггера данные по текущей строке еще не сохранены. Т.е. рассчитать-то сумму можно, но по текущей строке все-равно придется разницу добавлять. При этом с точки зрения равенства суммы в шапке и строках вероятность получить расхождения будет точно такой же. Я не вижу здесь никаких преимуществ. Только времени будет больше тратиться 2. Блокировки Цель блокировки - это запрет работы для другого пользователя. Собственно, какая разница, успеет другой пользователь обновить данные в шапке или нет? Триггер-то в любом случае будет менять самые последние данные. А так, нет никакого смысла в блокировке. Она не повлияет на корректность работы триггера. 3. В тело триггера добавить проверки на ошибки ввода Можно, конечно. Но это не "естественная" задача для триггера. Да и триггер выполняется слишком "поздно" для контроля ввода Цель триггера - это поддержание целостности данных. Синхронное изменение данных в разных записях и в разных таблицах. Вот обновление суммы в шапке - задача для триггера. А контроль ввода - это несколько другое и выполняется в других местах. В частности, в RULE уровня поля или записи Если все-таки контроль ввода будет перенесен в триггер, то следует иметь в виду, что штатно не предусмотрено возвращение текста ошибки из триггера. Он возвращает только логическое значение. .T. - успех, .F. - ошибка и отмена внесенных изменений Для возврата текста ошибки используют "костыль" в виде глобальной переменной (в штатной RI для этого используется массив gaErrors). Т.е. в случае ошибки в теле триггера сначала записывают текст ошибки в глобальную переменную, потом возвращают .F. А уже вне тела триггера анализируют код ошибки при сохранении и если это ошибка триггера, то считывают текст из этой глобальной переменной Исправлено 1 раз(а). Последнее : Владимир Максимов, 09.04.20 01:53 |
Re: Как работать с Trigger-ами? | |
---|---|
lulgu Сообщений: 1838 Дата регистрации: 30.11.2016 |
Опасное это слово - "триггер", раздразнили гусей.
Даже описания работы с триггерами не менее страшны, чем сами триггеры. И все это вместо небольшого CUSTOM-класса с парочкой процедур. |
Re: Как работать с Trigger-ами? | |
---|---|
ZenTigra Автор Сообщений: 514 Дата регистрации: 03.12.2004 |
Вот мне и нужно выяснить, стоит ли в моем случае связываться с триггерами. Я не вполне понимаю, для каких задач они применяются, вот спросил помощи у форумчан, и их ответом вполне доволен. Теперь буду пробовать, а нужно ли оно мне, или хватит класса с парочкой процедур. PS.Всем спасибо за советы. Исправлено 1 раз(а). Последнее : ZenTigra, 09.04.20 09:19 |
Re: Как работать с Trigger-ами? | |
---|---|
lulgu Сообщений: 1838 Дата регистрации: 30.11.2016 |
Фоксовские триггеры для практической работы непригодны, все это бла-бла-бла уже два десятка лет..
Такие задачи в фоксе практики обычно решают кто как может, так проще. А теоретики козыряют наборами SQL-языков, как своими. ЗЫ. В принципе, можно создать универсальный класс _Trigger, куда с умом вынести коды из RI Только смысла в этом немного, это возня на любителя. Исправлено 2 раз(а). Последнее : lulgu, 09.04.20 09:46 |
© 2000-2024 Fox Club  |