Обновление вместо вставки.

Модераторы: kdv, CyberMax

pum
Сообщения: 7
Зарегистрирован: 03 фев 2007, 15:49

Обновление вместо вставки.

Сообщение pum » 03 фев 2007, 16:12

Доброго времени суток всем!
Если кто-нибудь знает, подскажите, пожалуйста.
При вставке новой записи в таблицу, я проверяю наличие в этой таблице необходимой записи. Если нет, то просто добавляю. Если есть, то обновляю некоторые поля этой записи.
Собственно, вопрос: Как в триггере BeforeInsert остановить добавление
новой записи, не отменяя сделанные изменения и не используя exception.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 04 фев 2007, 23:14

рекомендую воспользоваться поиском, т.к. эта тема уже обсуждалась.
В общем случае вставку превратить в обновление в триггере на вставку нельзя. То есть, нужно пользоваться процедурой. Например как тут:
www.ibase.ru/devinfo/testiu.htm

pum
Сообщения: 7
Зарегистрирован: 03 фев 2007, 15:49

Сообщение pum » 13 фев 2007, 16:53

Спасибо, Дмитрий.
Так и делал (по первому варианту), но решил спросить, может есть способ обойтись триггером. Нету.
И еще вопрос. Как получить идентификатор записи, на котой произошла ошибка (применительно к третьему варианту)?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 13 фев 2007, 17:19

может есть способ обойтись триггером. Нету.
ну КАК тут можно обойтись триггером, объясните мне пожалуйста, а?
Честное слово - Вы не представляете, как триггеры работают, и уже пытаетесь туда какой-то изврат запихнуть.
Как получить идентификатор записи, на котой произошла ошибка
обработкой when. А Вы прямо так процедурой и шпарите? Статья ведь просто пример, плюс один из способов импорта - через external table.
там же и пример when есть.
или я не понимаю, о чем Вы спрашиваете. Можно поподробнее?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 13 фев 2007, 18:03

kdv писал(а):ну КАК тут можно обойтись триггером, объясните мне пожалуйста, а?
Если ССЗБ, то ведущие проктологи рекомендуют так:

Код: Выделить всё

CREATE TRIGGER ... BEFORE INSERT
as begin
  if (exists (select 1 from Table1 a1 where a1.id = new.id)) then begin
    update Table1 a
      set a.val1 = new.val1,
          a.val2 = new.val2,
          ...
      where a.id = new.id;
    new.id = -1;
  end
end

CREATE TRIGGER ... AFTER INSERT
as begin
  if (new.id < 0) then
    delete from Table1 a where a.id = new.id;
end
PS: Автор, это чиста теория, так делать не надо!

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 13 фев 2007, 18:22

А в глаз? :-D За смущение неокрепших умов? Это даже не теория, а искусственный этюд, предполагающий невозможность типа одноврменной вставки двух дубликатов даже с разными значениями ключа.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 13 фев 2007, 19:04

Merlin писал(а):невозможность типа одноврменной вставки двух дубликатов даже с разными значениями ключа.
:roll: чего-то я не понял этой фразы.
Как это "дубликаты с разными id" ? Какие ж они дубликаты?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 13 фев 2007, 20:17

Пардон муа, великим руский языка (С). Две пары дубликатов. Обоих будешь замещать -1. Компрене ву? (C)

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 13 фев 2007, 20:47

Думаешь, загнётся на конкурентной вставке? Хм.
Ну тогда "-1" заменяем на "-new.id".
Ы?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 13 фев 2007, 20:50

Тады в r_c загнётся на (exists (select 1 from Table1 a1 where a1.id = new.id)) ежели оно там есть, но ещё не закоммичено, или работаем в снапшоте и закоммичено после нашего старта.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 13 фев 2007, 21:05

Решение я придумывал для одной вставляющей транзакции :)
Щас прикину, можно ли как обойти...

mik83only
Сообщения: 5
Зарегистрирован: 21 окт 2005, 23:19

Сообщение mik83only » 25 апр 2007, 14:28

У меня похожая проблема, но только не нужно делать update, а просто проверять перед insert'ом, есть ли уже такие записи.
Извиняюсь за свою тупость, но после прочтения статьи не совсем понял - нужно все инсерты делать через хранимую процедуру и в ней уже проверять ?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 25 апр 2007, 15:13

mik83only писал(а):а просто проверять перед insert'ом, есть ли уже такие записи.
И что делать в случае, если есть?

mik83only
Сообщения: 5
Зарегистрирован: 21 окт 2005, 23:19

Сообщение mik83only » 25 апр 2007, 15:55

WildSery писал(а):
mik83only писал(а):а просто проверять перед insert'ом, есть ли уже такие записи.
И что делать в случае, если есть?
Насколько я понимаю - не вставлять, то есть ничего не делать.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 25 апр 2007, 16:03

Ну так бери первую или вторую процедуру, оставляй только ветку "INSERT" и будет щастье.
Можно конечно и с клиента пихать всё INSERT'ом, что уже есть отшибёт по PK, в клиенте перехватываешь.

mik83only
Сообщения: 5
Зарегистрирован: 21 окт 2005, 23:19

Сообщение mik83only » 25 апр 2007, 16:10

Так у меня проверка по трем полям сразу и они не PK.
Просто таких таблиц в которых нужно проверять на уникальность - несколько и я подумал, что писать для каждой процедуру на добавление - не совсем правильно и можно сделать как-то проще(со стороны клиента через запрос). Я заблуждаюсь ?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 25 апр 2007, 18:17

Посуди сам - с клиента ты делаешь два запроса, сперва проверка существования, затем вставка или ничего.
А в случае процедуры - один запрос, на вызов процедуры, дальше всё выполняется внутри сервера.

pum
Сообщения: 7
Зарегистрирован: 03 фев 2007, 15:49

Сообщение pum » 25 апр 2007, 22:55

Привет еще раз.
Написал, думал, что "светлые головы" что нибудь посоветуют по делу. Напрасно надеялся. Только посмеялись. ':twisted:'
Свои проблемы решил так. В таблице есть некое составное уникальное поле. Приложение (один из видов клиентов) постоянно осуществляет вставку (это о нем речь), остальные только читают, скрипт при перед backup удаляет лишнее. Вставка осуществляется только процедурой. При возникновении ошибки WHEN ANY DO (SQLCODE 803), т.е. попытка вставить новую уникальную запись, провожу поиск идентификатора записи, на которой встали, и обновляю ее, меняя некоторые значения не входящие в составное уникальное поле (ну, мне так надо).
А хотел я от Вас узнать, Нельзя ли, НЕ ДЕЛАЯ ДОПОЛНИТЕЛЬНОГО SELECT, в момент, когда процедура споткнулась на INSERT, узнать номер, ID или еще как выяснить идентификатор этой записи, которая содержит набор таких же значений составного поля, что и в запросе INSERT. ':?'

С уважением.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 26 апр 2007, 01:46

Написал, думал, что "светлые головы" что нибудь посоветуют по делу. Напрасно надеялся. Только посмеялись.
тупой вопрос - тупой ответ, извини за прямоту.
Нельзя ли, НЕ ДЕЛАЯ ДОПОЛНИТЕЛЬНОГО SELECT, в момент, когда процедура споткнулась на INSERT, узнать номер, ID или еще
см. цитату выше. В приведенной ссылке нормальный вариант когда сначала ИЩУТ запись, а потом по ее СУЩЕСТВОВАНИЮ или нет делают update или insert.
как выяснить идентификатор этой записи, которая содержит набор таких же значений составного поля, что и в запросе INSERT.
ты определись сначала, что у тебя является идентификатором записи. А потом подумай над тем, что ты спросил.
Если у тебя на таблице только ПК, то вопроса как такового нет. Если же есть еще и альтернативный ключ, то ты уж тогда как-нибудь сам разберись, чего ты пытаешься задублировать - или повторить значение ПК, или повторить значение альтернативного ключа.
В общем, с моделью данных разберись :)

mik83only
Сообщения: 5
Зарегистрирован: 21 окт 2005, 23:19

Сообщение mik83only » 26 апр 2007, 14:05

WildSery писал(а):Посуди сам - с клиента ты делаешь два запроса, сперва проверка существования, затем вставка или ничего.
А в случае процедуры - один запрос, на вызов процедуры, дальше всё выполняется внутри сервера.
Понятно, спасибо за консультацию :)

Ответить