Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

(Oracle) Как правильно написать триггер для автоприсвоения ID [MySQL]


Страницы:   1 2 3 4 5 6

ANB ©   (2005-09-27 14:12:00) 

Попробовал сделать так :

create or replace trigger GT_Product_PK_TR
 before insert on GT_Product
 for each row
declare
begin
 if :New.ID is null then
  select GT_Product_SQ.Nextval into :New.ID from dual;
 end if;
end GT_Product_PK_TR;

Получил проблему - если ID жестко задавать в инсертах, то сиквенс не мотается и потом лезут ошибки.
Переделал :

create or replace trigger GT_Product_PK_TR
 before insert on GT_Product
 for each row
declare
Cur_SQ number;
begin
 if :New.ID is null then
  select GT_Product_SQ.Nextval into :New.ID from dual;
 else
  select GT_Product_Firm_SQ.Currval into Cur_SQ from dual;
  while (Cur_SQ < :New.ID) loop
   select GT_Product_Firm_SQ.Nextval into Cur_SQ from dual;
  end loop;
 end if;
end GT_Product_PK_TR;

В таком варианте вроде, получше, но все равно можно нарваться на дублирование записей. Можно воткнуть еще проверку на существование уже сгенеренного ID и прокручивать сиквенс до нужного значения, но, во первых, полезут ошибки "таблица мутирует", во вторых это ничего особо не даст, т.к. если я умудрюсь в двух разных сессиях сгенерить один и тот же ID, то про триггер на них никак не поругается, так как записи еще не закоммичены, а проблема вылезет при коммите. Хотя, возможно, я не так понял механизм транзакций.


Val   (2005-09-29 15:03:00) [41]

>[63] Курдль ©   (29.09.05 14:30)

> Меня инетерсует не как "получить после", а как "получить
> до".

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


Курдль   (2005-09-29 15:02:00) [42]


> Danilka ©   (29.09.05 14:48) [67]
> Делаешь на клиенте запись в мастер-таблицу, затем, полученое
> значение ид (ретурнингом или еще как) прописываешь в детальных
> таблицах и уже их и апплишь.


"Делаешь на клиенте запись в мастер-таблицу". Т.е. ее записываешь в реальную БД, открыв транзакцию, и держишь ее открытой, пока не набьешь в БД всех зависимых?


Danilka   (2005-09-29 14:49:00) [43]

Курдль ©   (29.09.05 14:43)


Хотя твой вариант может быть и проще. Но я так не делал. :)


Danilka   (2005-09-29 14:48:00) [44]

Курдль ©   (29.09.05 14:43)

> Danilka ©   (29.09.05 14:35) [64]
> Подскажешь пример такой необходимости?
> Всегда идет сначала вставка в мастер-таблицу, а уж затем
> во все связанные.
> А иначе констрейнт просто не даст всавить в подчиненные,
>  когда в мастер-таблице еще нет записи.
> Буду премного благодарен, если сможешь переубедить, прям
> откроешь мне глаза.

А в чем противоречие с тем, что я написал выше?
На клиенте заполняешь группу датасэтов, например - одну запись в мастер-таблицу, и по нескольку в связанные. Потом, проверив по первичным признакам: DataBase.ApplyUpdates([dsMaster, dsSlave1, dsSlave2...]);
Но для этого надо заранее знать ID следующей записи в мастер-таблице!


Делаешь на клиенте запись в мастер-таблицу, затем, полученое значение ид (ретурнингом или еще как) прописываешь в детальных таблицах и уже их и апплишь.


Курдль   (2005-09-29 14:43:00) [45]


> Danilka ©   (29.09.05 14:35) [64]
> Подскажешь пример такой необходимости?
> Всегда идет сначала вставка в мастер-таблицу, а уж затем
> во все связанные.
> А иначе констрейнт просто не даст всавить в подчиненные,
>  когда в мастер-таблице еще нет записи.
> Буду премного благодарен, если сможешь переубедить, прям
> откроешь мне глаза.


А в чем противоречие с тем, что я написал выше?
На клиенте заполняешь группу датасэтов, например - одну запись в мастер-таблицу, и по нескольку в связанные. Потом, проверив по первичным признакам: DataBase.ApplyUpdates([dsMaster, dsSlave1, dsSlave2...]);
Но для этого надо заранее знать ID следующей записи в мастер-таблице!


Danilka   (2005-09-29 14:38:00) [46]

ANB ©   (29.09.05 14:05)
- есть еще варианты, когда на все таблицы используется один сиквенс или в качестве ИД генерится GUID. И все они имеют право на существование.


Кто-бы спорил.
Мне прочто непонятно зачем делать всякие лишние навороты, когда можно во всех случаях обойтись самым первым вариантом.
В том числе и тогда, когда сиквенс один на всех.


Danilka   (2005-09-29 14:35:00) [47]

Курдль ©   (29.09.05 14:30)
Меня инетерсует не как "получить после", а как "получить до".
Ведь нередко приходится на клиенте в один прием создавать туеву хучу записей во взаимосвязанных таблицах и знать значение первичного (внешнего) ключа заранее.


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


Курдль   (2005-09-29 14:30:00) [48]


> ANB ©   (29.09.05 14:05) [62]
> - автоикрементальность в MS SQL можно временно отключать
> и прописывать ID прямо в инсерте. При это счетчик почему
> все равно мотает. Я не являюсь пользователем MS SQL, посему
> точно уже не помню, как я это делал. Достать все поля после
> вставки нельзя, а вот автосгенеренный ID можно.


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

Меня инетерсует не как "получить после", а как "получить до".
Ведь нередко приходится на клиенте в один прием создавать туеву хучу записей во взаимосвязанных таблицах и знать значение первичного (внешнего) ключа заранее.

Напр. в оракле можно отправить запрос select SEQ_NAME.nextval from dualили в сайбэйсе select GetIdentity('TAVLE_NAME') from dummy. В IB тоже есть возможность получить значение генератора (не помню синтаксиса, типа select GEN_ID('GEN_NAME', 1) from rdb$database).
Как это будет выглядеть на MS SQL?


ANB   (2005-09-29 14:05:00) [49]


> Курдль ©   (29.09.05 13:23) [59]
- автоикрементальность в MS SQL можно временно отключать и прописывать ID прямо в инсерте. При это счетчик почему все равно мотает. Я не являюсь пользователем MS SQL, посему точно уже не помню, как я это делал. Достать все поля после вставки нельзя, а вот автосгенеренный ID можно.

> Danilka ©   (29.09.05 13:20) [58]
- есть еще варианты, когда на все таблицы используется один сиквенс или в качестве ИД генерится GUID. И все они имеют право на существование.


Val   (2005-09-29 13:26:00) [50]

эту идею фикс можно оформить в виде хп и для вставки использовать именно ее.


Sergey13   (2005-09-29 13:24:00) [51]

2[57] Danilka ©   (29.09.05 13:14)
Можно и так, только у АНБ вроде "задача" (или идея фикс!!! 8-) отказаться иногдаот сиквенса и заносить скриптом с прописанными жеско ИД-шниками.


Курдль   (2005-09-29 13:23:00) [52]


> ANB ©   (29.09.05 10:39) [43]
> Могу же я себе позволить работать в MS SQL напрямую с
> автоинкрементарным полем и при этом ничего не ломается ?


Это что, шутка? :-)  Как это "напрямую"? Т.е. взять и прописать в поле уникального идентификатора что попало? Везет вам, пользователям MS SQL!
А как, например, Вы на клиента можете получить уникальный идентификатор для выбранной таблицы?


Danilka   (2005-09-29 13:20:00) [53]

[56] ANB ©   (29.09.05 13:13)


А по-моему это ты сам себе злобный буратино, твоего самого первого варианта всегда хватало в том числе и на базе с тысячью таблиц и нескольких сотен сиквенсов.


Danilka   (2005-09-29 13:14:00) [54]

Sergey13 ©   (29.09.05 13:03)
2 ANB ©
Вот еще вспомнил. Я однажды делал подобное. Надо было сделать записи с жесткими кодами (типа значения по умолчанию, не важно). Так я просто сделал их отрицательными. И выделяются среди других и сиквенсу не мешают.


А можно сразу сиквенсу сделать шаг двойку, в базе которая для разработки сделать чтоб сиквенс начинался с двойки и спокойно в нее вносить всякие тестовые данные, удалять, а потом спокойно снимать скрипт на то что нужно и переносить в рабочую, ибо в рабочей ид-шники будут все нечетные, а в той - все четные.
:)


ANB   (2005-09-29 13:13:00) [55]


> Sergey13 ©   (29.09.05 12:46) [51]
- будет сам себе злостный буратино. К тому же можно это на клиенте проверить. Или в том же триггере.


ANB   (2005-09-29 13:12:00) [56]

Во, вот так я сделал и, вроде, работает :

create sequence Gt_Firm_Sq
minvalue 1
start with 1
increment by 1
nocache
order;
/
create or replace trigger Gt_Firm_Pk_Tr
before insert
on Gt_Firm
for each row
declare
Cur_ID                        number;
begin
if :new.ID is null then
 select Gt_Firm_Sq.nextval
   into :new.ID
   from dual;
else
 select (Us.Last_Number - 1)
   into Cur_ID
   from User_Sequences Us
  where Us.Sequence_Name = upper ('Gt_Firm_Sq');

 while (Cur_ID < :new.ID) loop
  select Gt_Firm_Sq.nextval
    into Cur_ID
    from dual;
 end loop;
end if;
end Gt_Firm_Pk_Tr;
/

Только от выключения/включения не защищает. Но на этот случай пусть уже сами потом сиквенс мотают. Можно при запуске клиента проверять включенность триггеров и соответствие сиквенсна ИД.


Sergey13   (2005-09-29 13:03:00) [57]

2 ANB ©
Вот еще вспомнил. Я однажды делал подобное. Надо было сделать записи с жесткими кодами (типа значения по умолчанию, не важно). Так я просто сделал их отрицательными. И выделяются среди других и сиквенсу не мешают.


Danilka   (2005-09-29 12:53:00) [58]

Val ©   (29.09.05 12:49)
>ANB ©
боге мой :(
Q:Как правильно написать триггер для автоприсвоения ID
A:

create or replace trigger GT_Product_PK_TR
before insert on GT_Product
for each row
declare
begin
select GT_Product_SQ.NextVal into :New.ID from dual;
end GT_Product_PK_TR;

Всё. Автоприсвоение - это _автоприсвоение_ - никаких вставок с заданным id. Проблемы либо надуманы, либо неверно спроектирована логика работы с таблицей.


ну не совсем так. всетаки лучше проверять на null.
например, вариант когда инфа из нескольких баз сливается в одну.
тогда сиквенс дергать ненадо.
правда, и перематывать его потом тоже ненадо, если заранее предусмотреть такой вариант, и длякаждой базы предусмотреть свой диапазон значений, либо шаг отличный от 1 + начальное смещение для каждой базы.

а вот разрешить юзерам самому задавать ид это по-моему глупо.


Val   (2005-09-29 12:49:00) [59]

>ANB ©
боге мой :(
Q:Как правильно написать триггер для автоприсвоения ID
A:

create or replace trigger GT_Product_PK_TR
before insert on GT_Product
for each row
declare
begin
 select GT_Product_SQ.NextVal into :New.ID from dual;
end GT_Product_PK_TR;

Всё. Автоприсвоение - это _автоприсвоение_ - никаких вставок с заданным id. Проблемы либо надуманы, либо неверно спроектирована логика работы с таблицей.


Danilka   (2005-09-29 12:46:00) [60]

ANB ©   (29.09.05 12:25)

> Fay ©   (29.09.05 12:21) [46]
- да нарвался уже. Я же постил. Кстати, в НЕКОТОРЫХ случаях может и не дать, но редко. Как раз в моем случае я на нее сразу нарвался. Попробовал заменить на nextval, но обнаружил уже логическую ошибку : если в клиентском приложении я ручками мотаю сиквенс и присваиваю жестко полученный ID. то триггер проматывает его лишний раз.


А зачем тебе его на клиенте дергать?
Пущщай в триггере и дергается, а узнать какое именно значение записалось можео с помощью ретурнинга.


Страницы:   1 2 3 4 5 6

Наверх

Титульная страница Поиск, карта сайта Написать письмо