Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > БД в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 17.08.2013, 16:03   #1
Pashka_cool
 
Регистрация: 17.08.2013
Сообщений: 8
Восклицание Update or Insert и FireBird 2.5.2

Коллеги, выручайте. Не работает "Update or Insert" команда, точнее при ситуации INSERT-а не отрабатывает триггер "BEFORE INSERT" по таблице, который берёт значение ключа из геренатора и вторая команда уже выбивает ошибку нарушения уникальности записей.
Попытки выполнить задачу через MERGE вообще неуспешны, т.к. MERGE не работает, когда в условии USING указана эта же таблица. Перебрал кучу вариантов - результат нулевой. Вот код добавления:
Код:
  update or INSERT into a_ftypes (ftname, ftdescr, ft_id) VALUES('DEFAULT',        '', 0) matching (ft_id) returning a_ftypes.indexid into :var_index;
  update or INSERT into a_ftypes (ftname, ftdescr, ft_id) VALUES('USER INFO',      '', 1) matching (ft_id) returning a_ftypes.indexid into :var_index;
  update or INSERT into a_ftypes (ftname, ftdescr, ft_id) VALUES('TIME DIAPOSONE', '', 2) matching (ft_id) returning a_ftypes.indexid into :var_index;
Вторая строка выбивает. Упоминать в перечисленных полях индексное вместе со значением из генератора - работает, но будет всегда менять значение индекса, что абсурдно.
Кстати пробую выполнять этот код в ХП через IBExpert 2013.6.29.1

Последний раз редактировалось Stilet; 17.08.2013 в 17:28.
Pashka_cool вне форума Ответить с цитированием
Старый 17.08.2013, 17:30   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
но будет всегда менять значение индекса, что абсурдно
В каком смысле? Поясни эту фразу.

Кстати, я лично в FB предпочитаю такую конструкцию:
Код:
INSERT into a_ftypes (ftname, ftdescr, ft_id) VALUES('DEFAULT',        '', (select max(ft_id)+1 from a_ftypes))
По крайней мере она меня никогда не подводила в отличии от генераторов.
I'm learning to live...

Последний раз редактировалось Stilet; 17.08.2013 в 17:32.
Stilet вне форума Ответить с цитированием
Старый 17.08.2013, 18:45   #3
Pashka_cool
 
Регистрация: 17.08.2013
Сообщений: 8
По умолчанию

Дело в том, что приведённый код ниже вызывается на регулярной основе. Я лишь в нём значения явно задал, но будут на самом деле параметры. Некоторые из параметров тоже уникальны, как и первичный ключ. Если код вызвать дважды, то второй раз сработает UPDATE, а не INSERT, что вполне соответствует инструкции, но при обновлении будет и значение ключа подставлено уже новое, т.к. оно из генератора получается - я т.к. ссылочная целостность никем не отменена, то зависимые записи в другой таблице просто не позволят сделать такой UPDATE.
При этом использовать вместо генератора поиск максимального значения - нехороший подход. Если система многопользовательская (отмечу, что коилчество одновременных сессий - несколько сотен), то может быть получено одинаковое значение ключа (так и было у меня на заре разработок). Генератор эту ситуацию исключает.

Смысл прост, если указать явно вставку значения ключа, типа:
update or INSERT into a_ftypes (indexid, ftname, ftdescr, ft_id) VALUES(next value for gen_a_ftypes_id, 'DEFAULT','', 0) matching (ft_id) returning a_ftypes.indexid into :var_index;
то после второго вызова этой же операции произойдёт уже не INSERT, а UPDATE, что соответствует инструкции, но... будет обновлено значение первичного ключа из генератора на новое. А это нарушит ссылочную целостность таблиц. Триггер на пред-инсерт должен был разрулить это автоматом (т.е. как указано в первом сообщении значение ключа не упоминать в полях и параметрах). Но не работает. Хотя при передаче значения NULL он бы работал! Но тогда UPDATE не допускает такую запись.
А упомянутый вам вариант с поиском максимума и по времени будет долог при ёмкой таблице и ошибки с ним пойдут, когда количество сессий будет в несколько сотен одновременно (я это уже давно проходил, больше не посторяю эту ошибку).

Последний раз редактировалось Stilet; 17.08.2013 в 21:30.
Pashka_cool вне форума Ответить с цитированием
Старый 17.08.2013, 19:20   #4
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,776
По умолчанию

Мне кажется, что в values на место ft_id нужно написать что-то вроде:
Код:
  case when ft_id is null then next value for ge_a_ftypes_id else ft_id end
Либо, если в Firebird есть функция-макрос типа nvl в Oracle, использовать ее:
Код:
  nvl(ft_id, next value for ge_a_ftypes_id)
Vapaamies вне форума Ответить с цитированием
Старый 17.08.2013, 21:33   #5
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Хм... Если честно мне кажется что сам механизм работы с БД продуман плохо...
Такие телодвижения с триггерами... Не слабо, так сказать.
В общем у меня нет идей, кроме того что сказал выше. Нужно анализировать твою разработку - зачем понадобилась такая сложность.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 17.08.2013, 22:35   #6
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,776
По умолчанию

С чашкой вечернего чая я тоже понял, что теперь не понимаю, чего же хочет автор. Присоединяюсь к Stilet-у, хотелось бы услышать изначальную задачу.
Vapaamies вне форума Ответить с цитированием
Старый 18.08.2013, 17:17   #7
Pashka_cool
 
Регистрация: 17.08.2013
Сообщений: 8
По умолчанию update or select in FireBird 2.5.2

Ок, повторюсь с задачей, но более разборчиво:
Есть мастер-таблица и 10 таблиц-подчинённых к ней (по ходу кол-во не важно, просто указываю, как есть).
Есть общая процедура добавления записи во все эти таблицы. Но при первой итерации не во все подчинённые таблицы будет внесена запись, а лишь в часть из них. При второй итерации (обновления уже) в мастере уже запись есть. В части подчинённых - тоже, но в ещё некоторых подчинённых таблицах нет и только в этот (второй раз) будут вноситься данные, т.е. в них будет INSERT,а в остальные уже UPDATE. К примеру: при регистрации пользователь внёс только часть данных обязательных, а позже решил внести дополнительные + подредактировать уже имеющиеся. Так вот конструукция UPDATE or INSERT тут как раз и хороша, но с ней проблема в работе с уникальными ключами записей. Совершенно ничего сложного не происходит как раз. ЗАдача из разряда естественных. Поэтому в общей процедуре находиться вся пачка этих UPDATE or INSERT по каждой и таблиц-подчинённых.
Да вы сами попробуйте выполнить дважды одну и туже команду эту и увидите проблему. Напишите команду 2 раза подряд (эквивалет вызвать её дважды). И проблема тут же на лицо с уникальным ключом.
Если его передавать, как null, то ошибка пре-компиляции из-за UPDATE, если указать генератор, то повторная сработка сменит уникальный ключ на новое значение. Если не указывать вообще поле уникального ключа в этом операнде, то два подряд INSERT-а не работают (хотя триггер должен отработать, но нет, не работает)! На втором INSERT-е сразу ошибка нарушения уникальности по ключу.
Я лишь полагаю, что никто не использовал этот операнд подряд много раз, поэтому проблему и не уловил. Да и MERGE вообще не работает в этой же ситуации. Все примеры MERGE в Инете используют в качестве USING выражение по другой таблице, а не по той же, в которую этот операнд должен выбрать INSERT или UPDATE. НЕт таких рабочих примеров! Засада какая-то, блин.
По части NVL, то в FireBird нет эквивалента. C ORACLE я порядочно поработал, потому в курсе, о чём речь. По части использовать case - дело в том, что я не передаю в эту процедуру значение поля индексного. Потому CASE-у не с чем оперировать.

Последний раз редактировалось Pashka_cool; 18.08.2013 в 17:23.
Pashka_cool вне форума Ответить с цитированием
Старый 18.08.2013, 18:44   #8
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
при первой итерации не во все подчинённые таблицы будет внесена запись
Стесняюсь спросить, почему?
Цитата:
сами попробуйте выполнить дважды одну и туже команду эту и увидите проблему.
Вот тот способ что я описал выше таких проблем мне никогда не давал.
Я именно так дописываю недостающие данные в таблицы.
Сначала предположим проделываю несколько UPDATE по условию чтоб отредактировать то что уже имеется, если такого нет, редактирование не сработает, а потом инсертами добавляю.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 18.08.2013, 18:53   #9
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Зачем update or INSERT в таблицу, в которой значение ключа триггером генерируется? Эта конструкция для таблиц, в которых это значение программно создается и не более того
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 18.08.2013, 19:54   #10
Pashka_cool
 
Регистрация: 17.08.2013
Сообщений: 8
По умолчанию

Одним словом я вам, коллеги, задал вопрос о нерабочих двух конструкциях в FireBird-е, которые должны работать, но заставить их работать правильно в моей ситуации не выходит (хотя ситуация проста и инструкции явно в чём то недопилены). Пусть так. Тогда упрощу задачу до немогу. Просто задам вопрос:
Есть таблица, в ней 1 000 000 записей. Мне нужно внести или обновить ещё одну. Я не знаю, есть она или её ещё нет в таблице. Как поступать? Искать её на наличие, а по результату уже выполнять UPDATE или INSERT? И какова будет скорость Базы при частых таких запросах?
Именно поэтому я пытался прибегнуть к упомянутым двум видам инструкций и получил облом. Как сделать "классически" - я прекрасно понимаю. Но скорость хорошую это не даст, когда записей несколько лимонов и одновременных рабочих сессий несколько сотен!
Pashka_cool вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
UPDATE OR INSERT по нескольким таблицам в одной процедуре Dozent БД в Delphi 1 21.02.2013 16:40
Invalid insert or update value(s): object columns are constrained BarakudaX777 БД в Delphi 2 17.09.2012 08:28
UPDATE, INSERT, DELETE в DataGridView C# Ramirag Помощь студентам 3 04.09.2011 13:24
выполнение запросов(Insert,Update) Rio309 C# (си шарп) 1 20.03.2011 17:10
insert и update Tanusha SQL, базы данных 4 13.03.2009 14:47