Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.11.13;
Скачать: CL | DM;

Вниз

(Oracle) Как правильно написать триггер для автоприсвоения ID   Найти похожие ветки 

 
ANB ©   (2005-09-27 14:12) [0]

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

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, то про триггер на них никак не поругается, так как записи еще не закоммичены, а проблема вылезет при коммите. Хотя, возможно, я не так понял механизм транзакций.


 
Андрей Жук ©   (2005-09-27 14:18) [1]

В MySQL появились триггеры???


 
Sergey13 ©   (2005-09-27 14:20) [2]

2ANB ©   (27.09.05 14:12)
Че-то ты мудришь, ИМХО.

>если ID жестко задавать в инсертах
Как жестко? Нафига жестко?
Можно и гвозди конечно микроскопом забивать. Вопрос - зачем?

select GT_Product_Firm_SQ.Currval
может и ошибку дать, если сессия еще не дергала этот сиквенс.


 
kesha ©   (2005-09-27 14:26) [3]

if :new.ID is null then
  SELECT GT_Product_SQ.Nextval into :New.ID from dual;
 end if;

CREATE SEQUENCE "xxx"."GT_Product_SQ" INCREMENT BY 1 START
   WITH 1 MAXVALUE 1.0E28 MINVALUE 1 CYCLE
   CACHE 20 ORDER;

pri vstavke "ID" - vsegda NULL


 
Sergey13 ©   (2005-09-27 14:31) [4]

2[3] kesha ©   (27.09.05 14:26)
Это все зачем?
Это ты все в тригер хочешь написать? И ты думаешь будет работать? Мне кажется, даже не откомпилится.
Да и по смыслу... вернее смысла я не вижу.


 
Андрей Жук ©   (2005-09-27 14:42) [5]

Как делаю я. У меня есть процедура, которая по имени таблицы возвращает следующий ID по сиквенсу. Процедурка отрабатывает мгновенно. После чего на клиенте есть уже уникальный ID, который и вставляем в insert.


 
kesha ©   (2005-09-27 14:56) [6]


> Sergey13 ©   (27.09.05 14:31) [4]


CREATE SEQUENCE -> ne v triggere, a v base.

ANB:
esli tebe posle Insert gde-to nuzhen ID, to kak [5], tolko ne Procedure a Function:
  Inset into Table(ID, Field1) Values(Get_New_ID(Table), xxx);

esli tebe ID ne nuzgen:
 Inset into Table(Field1) Values(xxx);


 
DenK_vrtz ©   (2005-09-27 15:09) [7]


> if :New.ID is null then
>  


зачем это условие? Если вставка данных то :New.ID изначально null

select sqИмяПоследовательности.nextval into :new.id from dual; и больше никаких извращений


 
Sergey13 ©   (2005-09-27 15:10) [8]

2[6] kesha ©   (27.09.05 14:56)
Тогда я не понял твоего
>pri vstavke "ID" - vsegda NULL

>esli tebe posle Insert gde-to nuzhen ID, to kak [5], tolko ne Procedure a Function:
 Inset into Table(ID, Field1) Values(Get_New_ID(Table), xxx);
Как ты его отсюда получишь на клиенте?


 
Sergey13 ©   (2005-09-27 15:17) [9]

2[7] DenK_vrtz ©   (27.09.05 15:09)
>зачем это условие? Если вставка данных то :New.ID изначально null

Inset into Table(ID, Field1) Values(99999999, "xxx")
и где тут NULL?


 
DenK_vrtz ©   (2005-09-27 15:20) [10]

>Sergey13 ©   (27.09.05 15:17) [9]

Зачем явно задавать значение :new.ID, если он берется из последовательности и формируется автоматически?


 
DenK_vrtz ©   (2005-09-27 15:21) [11]

т.е. не он, а оно! :)


 
Курдль ©   (2005-09-27 15:27) [12]

Странное сочетание "oracle + MySQL" :)

Надеюсь, что это очепятка.
А как подключаетесь к ораклу? Если при помощи наиболее оптимальных для Delphi и испытанных в боях компонентов DOA, то им достаточно указать последовательность, связанную с идентификатором и они все сделают сами!


 
Sergey13 ©   (2005-09-27 15:28) [13]

2[10] DenK_vrtz ©   (27.09.05 15:20)
Его можно (вернее нужно) взять оттуда-же, но до вставки. Например, что бы знать что вставлять в поле связи детальной таблицы.


 
Desdechado ©   (2005-09-27 15:29) [14]

2 ANB [0]
первого варианта достаточно, если не будешь мудрить с придумыванием из головы ID для вставки в таблицу

после INSERT можно узнать ID перезапросом по уникальной комбинации полей или используя фичу Оракла:
INSERT .... RETURNING ... INTO ...


 
DenK_vrtz ©   (2005-09-27 15:33) [15]

>Sergey13 ©   (27.09.05 15:28) [13]

Или я чего пропустил, или детальные таблицы причем? :)


 
ANB ©   (2005-09-27 15:38) [16]

Ой ой. Как много ответов.
1. Отмечал оракл, но так как на форуме бага, то написал еще и в скобках тип БД.
2. Везде на всякий случай и стоит первый вариант (если ручками изнутри табличку править, то очень удобно), но нарвался на проблему : после создания таблиц схемы я скриптом заполняю начальные данные (справочники) и мне удобно писать там константы, а сиквенс при этом не перемотался и когда начинаешь таблицу корректировать ручками (тут уже все равно, ODAC генерит ID или я сам) получаю ошибку дублирования PK.
2-го варианта будет достаточно ?
ЗЫ. Вернуть ID на клиента, если припрет, не проблема через returning.


 
Sergey13 ©   (2005-09-27 15:40) [17]

2[15] DenK_vrtz ©   (27.09.05 15:33)
>Или я чего пропустил, или детальные таблицы причем? :)
При том, что они встречаются. И достаточно часто. И в них иногда надо что-то вставлять. 8-)


 
Sergey13 ©   (2005-09-27 15:44) [18]

2[16] ANB ©   (27.09.05 15:38)
Создавай сиквкенсы и тригера после заполнения. Начальное значение для сиквенса бери как Max+1 ИДшника таблицы.


 
ANB ©   (2005-09-27 15:45) [19]

Прошу прощения, в этом триггере и правда была синтаксическая ошибка. Вот так он выглядит в реале :

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_Sq.currval
   into Cur_Sq
   from dual;

 while (Cur_Sq < :new.ID) loop
  select Gt_Product_Sq.nextval
    into Cur_Sq
    from dual;
 end loop;
end if;
end Gt_Product_pk_Tr;


 
ANB ©   (2005-09-27 15:46) [20]


> Sergey13 ©   (27.09.05 15:44) [18]
- думал и над этим. Как то неуниверсально получится.


 
Desdechado ©   (2005-09-27 15:51) [21]

причем тут универсальность, если заполнение таблиц скриптом выполняется единожды?


 
ANB ©   (2005-09-27 15:51) [22]


> Sergey13 ©   (27.09.05 14:20) [2]
- точно, ошибку выдала. Вот блин.


 
ANB ©   (2005-09-27 15:52) [23]


> Desdechado ©   (27.09.05 15:51) [21]
- то есть лучше вернуться к первому варианту ?


 
DenK_vrtz ©   (2005-09-27 15:56) [24]

>ANB ©   (27.09.05 15:46) [20]

Если вариант Sergey13 ©   (27.09.05 15:44) [18] не устраивает(и почему он не универсальный?), то создать две последовательности. Первая идет по четным - вставляешь данные ты, вторая идет по нечетным - вставляет данные кто-то другой


 
Sergey13 ©   (2005-09-27 15:57) [25]

2[23] ANB ©   (27.09.05 15:52)
ИМХО, да. Можно, если хочется сильно, отдельный скрипт наваять на коррекцию сиквенсов по текущим значениям таблиц. Все лучше, чем лишний код в базе годами крутить.


 
kesha ©   (2005-09-27 16:07) [26]


> Sergey13 ©   (27.09.05 15:10) [8]


smotrja dlja 4ego tebe etot ID:
1: esli tol"ko Insert (vstavili i sabili) -> togda NULL
2: esli Insert delaet Function, kotoraja fozvrazhaet ID -> togda sna4ala
   .NEXTVAL into xxx, potom Insert s etim xxx


 
Sergey13 ©   (2005-09-27 16:24) [27]

2[26] kesha ©   (27.09.05 16:07)
Если честно - моя твоя не сильно понимай.


 
mr.IL ©   (2005-09-27 16:27) [28]

Народ, а не проще написать СП , в нее передавать значения будущей записи, в ней получать значение генератора, делать инсерт, а из нее получать ид.


 
ANB ©   (2005-09-27 16:27) [29]


> Sergey13 ©   (27.09.05 16:24) [27]
- если честно - моя его тоже не понимай.


 
Sergey13 ©   (2005-09-27 16:31) [30]

2 [28] mr.IL ©   (27.09.05 16:27)
А по твоему проще? И что будет в этой СП (ХП наверное?)? Тот же запрос?


 
ANB ©   (2005-09-27 16:36) [31]


> Sergey13 ©   (27.09.05 16:31) [30]
- сделал, как ты подсказал. Вернул триггер к первому варианту, а после вставок выполняю перемотку сиквенсов. Вроде, работает.

ЗЫ. Есть куча вариантов через ХП, присвоение ID прямо в инсерте, но они накладывают ограничения на возможности работы с таблицей и ID. При наличии триггера я могу пользоваться как всеми уже указанными способами, так и лениво инсертить в таблицу без указания ID и все будет работать.


 
mr.il ©   (2005-09-27 16:44) [32]

Ну да, ХП. Ну абстрактно так:
Процедура (Имя  Строка)
IS (ид  Число)
Тело процедуры
ид = секвенс.NextVal
insert into Таблица (ид_поле, имя_поле)
values (ид, имя)

Прошу простить, пишу абстракно, проверить не на чем.


 
Sergey13 ©   (2005-09-27 16:50) [33]

2 [32] mr.il ©   (27.09.05 16:44)
И чем это проще чем (абстрактно)
insert into Таблица (ид_поле, имя_поле) values (секвенс.NextVal, имя) returnung id into :id
?


 
ANB ©   (2005-09-27 16:52) [34]


> mr.il ©   (27.09.05 16:44) [32]

Вообще то обычно процедуры вставки в пакет запихивают. А заодно и для апдейта. Потом конечным пользователям даются права на чтение из таблицы, и на исполнение этих процедур. А в теле процедуры проверяются бизнес правила и права пользователя на изменения таблицы.
Но мне для этой задачи этого не нужно. Так как защита не нужна. Чисто внутренний проект.


 
ANB ©   (2005-09-27 16:53) [35]

ЗЫ. В моем случае оптимально
> Sergey13 ©   (27.09.05 16:50) [33]

(Так примерно ODAC и делает)


 
Sergey13 ©   (2005-09-27 16:59) [36]

2[34] ANB ©   (27.09.05 16:52)
> Вообще то обычно процедуры вставки в пакет запихивают.  А заодно и для апдейта.
А я обычно вообще ХП для этого не использую. Это дело вкуса и конкретных условий, ИМХО.


 
ANB ©   (2005-09-27 17:03) [37]


> Sergey13 ©   (27.09.05 16:59) [36]
- эт точно. Просто у нас в конторе такой подход.


 
mr.il ©   (2005-09-27 17:06) [38]

На счет пакета полностью согласен. У меня был вопрос в принципе, об исключении из клиента информации о правилах вставки.
Отдельно спасибо Sergey13, об этом: B>returnung id into :id я не знал


 
ANB ©   (2005-09-29 09:15) [39]

Таки не нравиться мне то, что получилось. Получается, клиент должен сам заботится о синхронизации сиквенса и ID таблицы. Может таки при ID is null проверять в цикле, что очередное значение сиквенса не конфликтует с ID ? В одной конторе так и сделано, но вылезает другая грабля - по одной записи нормально вставляются, а при пакетной вставке вылезает мутация таблицы.


 
Sergey13 ©   (2005-09-29 09:52) [40]

2[39] ANB ©   (29.09.05 09:15)
А откуда ноги растут у твоей озабоченности? С чего бы вдруг юзер стал вводить левые значения и каким образом? Шаловливыми ручками всегда можно вмешаться и на каждый узерский чих заплат не напишешь. ИМХО.


 
ANB ©   (2005-09-29 10:05) [41]


> Sergey13 ©   (29.09.05 09:52) [40]
- не, под клиентом я подразумевал клиентское приложение. Я видел уже несколько решений, но они все не очень универсальны и в каждом есть возможность граблей. Просто сейчас рисую небольшой проектик и на нем хотел бы отработать технологию. Если юзер ручками введет дубль, то, ессно, правильным будет поругаться и послать его.


 
Sergey13 ©   (2005-09-29 10:34) [42]

2[41] ANB ©   (29.09.05 10:05)
>- не, под клиентом я подразумевал клиентское приложение.
Я догадался. 8-)
Потому и спросил. Если в прикладе прописана вставка ИД из сиквенса, как в таблице появятся левые (не от туда) значения? Из "Плюсов" и "Девелоперов"? Так тогда надо безопасностью заниматься, а не сиквенсы "выравнивать" .
ИМХО.


 
ANB ©   (2005-09-29 10:39) [43]


> Sergey13 ©   (29.09.05 10:34) [42]

А если встеблится добавить скриптиком чего-нибудь ? Со связками ? Могу же я себе позволить работать в MS SQL напрямую с автоинкрементарным полем и при этом ничего не ломается ? Плюс пока приклад пишу я, а вот развивать - вовсе не факт.


 
Sergey13 ©   (2005-09-29 11:05) [44]

2 [43] ANB ©   (29.09.05 10:39)
> А если встеблится добавить скриптиком чего-нибудь ? Со связками ?

Скриптик писать надо с учетом этого или чистить за собой, как уже советовалось в [25]. Это, ИМХО, разумнее, нежели (повторяюсь опять же) "лишний код в базе годами крутить"

>Могу же я себе позволить работать в MS SQL напрямую с автоинкрементарным полем и при этом ничего не ломается ?

Про это не знаю, не работал.

>Плюс пока приклад пишу я, а вот развивать - вовсе не факт.

Тогда это будет не твоя проблема. 8-)


 
ANB ©   (2005-09-29 11:47) [45]


> Тогда это будет не твоя проблема. 8-)
- так не солидно. Мне ж за это денежку заплатят. Сверх зарплаты.


 
Fay ©   (2005-09-29 12:21) [46]

2 ANB ©   (27.09.05 15:45) [19]

Обратите внимание на [2]. Sergey13 совершенно прав:
>> select GT_Product_Firm_SQ.Currval
>> может и ошибку дать, если сессия еще не дергала этот сиквенс.

Могу только добавить, что не "может" дать ошибку, а ДАСТ 8)


 
ANB ©   (2005-09-29 12:25) [47]


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


 
Sergey13 ©   (2005-09-29 12:33) [48]

2ANB ©   (29.09.05 12:25)
Добраться до значения сиквенса ведь можно и через
select * from all_sequences
Может это тебя натолкнет на что полезное?
Хотя я по прежнему считаю, что ты перемудриваешь. 8-)


 
ANB ©   (2005-09-29 12:40) [49]


> Sergey13 ©   (29.09.05 12:33) [48]
- хм. А таки я попробую. Кстати, таки придется втыкать проверку и в Is null. Может кому всеблится отключить триггер, накидать записей, а потом включить. И сиквенс таки не перемотается. Никто не знает, как не напарываться на мутацию при обращении к этой же таблице в триггерре ?


 
Danilka ©   (2005-09-29 12:46) [50]

ANB ©   (29.09.05 12:25)

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


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


 
Sergey13 ©   (2005-09-29 12:46) [51]

2 [49] ANB ©   (29.09.05 12:40)
А если какому дураку захочется ввести ИД=максимальному значению сиквенса, или около того?


 
Val ©   (2005-09-29 12:49) [52]

>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:53) [53]

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 + начальное смещение для каждой базы.

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


 
Sergey13 ©   (2005-09-29 13:03) [54]

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


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

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

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;
/

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


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


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


 
Danilka ©   (2005-09-29 13:14) [57]

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


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


 
Danilka ©   (2005-09-29 13:20) [58]

[56] ANB ©   (29.09.05 13:13)


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


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


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


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


 
Sergey13 ©   (2005-09-29 13:24) [60]

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


 
Val ©   (2005-09-29 13:26) [61]

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


 
ANB ©   (2005-09-29 14:05) [62]


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

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


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


> 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?


 
Danilka ©   (2005-09-29 14:35) [64]

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


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


 
Danilka ©   (2005-09-29 14:38) [65]

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


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


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


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


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


 
Danilka ©   (2005-09-29 14:48) [67]

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

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

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


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


 
Danilka ©   (2005-09-29 14:49) [68]

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


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


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


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


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


 
Val ©   (2005-09-29 15:03) [70]

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

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

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


 
Danilka ©   (2005-09-29 15:06) [71]

Курдль ©   (29.09.05 15:02)

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

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


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


 
Курдль ©   (2005-09-29 15:09) [72]


> Val ©   (29.09.05 15:03) [70]


При работе с компонентами "DOA", например, идентификатору ставится в соответствие последовательность в дизайн-тайме прямо в инспекторе объектов.
Я, видимо, так и не понял, в чем проблема автора :(


 
Val ©   (2005-09-29 15:11) [73]

думаю, никто не понял :)


 
ANB ©   (2005-09-29 15:40) [74]


> Курдль ©   (29.09.05 15:09) [72]


> Val ©   (29.09.05 15:11) [73]

Чисто принципиально, в таблицы можно писать данные не только из программы - клиента, когда можно просто настроить компоненты (это и в OADC работает и в DOA). И проблема с получением автосгенеренных в триггере значений у меня не стоит, т.к. в оракле есть returning (кстати, в MS SQL есть @identity(если я синтаксис не перепутал)).


 
Val ©   (2005-09-29 15:57) [75]


> И проблема с получением автосгенеренных в триггере значений
> у меня не стоит

что я и говорил ранее. причем невзирая на returning.


 
Курдль ©   (2005-09-29 16:04) [76]


> ANB ©   (29.09.05 15:40) [74]
>
>
> > Курдль ©   (29.09.05 15:09) [72]
>
>
> > Val ©   (29.09.05 15:11) [73]
>
> Чисто принципиально, в таблицы можно писать данные не только
> из программы - клиента, когда можно просто настроить компоненты
> (это и в OADC работает и в DOA). И проблема с получением
> автосгенеренных в триггере значений у меня не стоит, т.к.
>  в оракле есть returning (кстати, в MS SQL есть @identity(если
> я синтаксис не перепутал)).
>


1. Мало кто понял, зачем все эти тибидоханья? :)
Чтобы вручную установить currval последовательности? Так оно и так устанавливается вручную!

2. @@identity есть, но доступен только В МОМЕНТ ИСПОЛНЕНИЯ DML!
Его нельзя вынуть запросом!


 
Fay ©   (2005-09-29 16:10) [77]

2 Курдль ©   (29.09.05 16:04) [76]
>> Его нельзя вынуть запросом!
В каком смысле?


 
Курдль ©   (2005-09-29 16:13) [78]


> Fay ©   (29.09.05 16:10) [77]
> В каком смысле?


Как заранее получить следующее уникальное значение идентификатора определенной таблицы в MS SQL?


 
Danilka ©   (2005-09-29 16:29) [79]

Курдль ©   (29.09.05 16:13)
Как заранее получить следующее уникальное значение идентификатора определенной таблицы в MS SQL?


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


 
ANB ©   (2005-09-29 16:38) [80]


> Курдль ©   (29.09.05 16:13) [78]


> Как заранее получить следующее уникальное значение идентификатора
> определенной таблицы в MS SQL?

- а зачем ?
Открываем транзакцию
Инсертим в мастер-таблицу
Узнаем ID добавленной записи
Инсертим в подчиненные таблицы
Коммитим.


 
Fay ©   (2005-09-29 16:38) [81]

2 Курдль ©   (29.09.05 16:13) [78]
>> Как заранее получить следующее уникальное значение
>> идентификатора определенной таблицы в MS SQL?
Никак, но как это связано с "в оракле есть returning" ?

2 Danilka ©   (29.09.05 16:29) [79]
на самом деле, таких примеров можно встретить произвольное количество.
Моему любимому MSSQL действительно очень не хватает тригеров before и генераторов (которые не зависят от транзакций).


 
ANB ©   (2005-09-29 16:40) [82]


> Как заранее получить следующее уникальное значение идентификатора
> определенной таблицы в MS SQL?
- а посмотреть и перемотать можно и ручками. Причем в обе стороны. Но лучше так не делать.


 
Курдль ©   (2005-09-29 16:41) [83]


> Собственно, именно такой пример от тебя я и хотел услышать.


Автор писал про оракл:


> ANB ©   (27.09.05 15:38) [16]
> 1. Отмечал оракл, но так как на форуме бага, то написал
> еще и в скобках тип БД.


Как получить ID заранее с 3-х СУБД я привел в [63]! А вот как это сделать в MS SQL - я не знаю! Но чую, что кто-то знает! :)  То ли SCOPE_IDENTITY, то ли нечто похожее!


 
ANB ©   (2005-09-29 16:42) [84]


> Моему любимому MSSQL действительно очень не хватает тригеров
> before
- хоть я MS SQL и не люблю, но вот логика триггеров мне там больше понравилась. Во всяком случае, мутаций таблиц там не бывает.


 
Fay ©   (2005-09-29 16:43) [85]

2 ANB ©   (29.09.05 16:40) [82]
Такое "можно" называется "нельзя".


 
ANB ©   (2005-09-29 16:45) [86]


> Курдль ©   (29.09.05 16:41) [83]
- ты можешь получить только текущее значение. Следующее же - это + 1, но так делать не кузяво, так как есть вероятность, что пользователь нарвется на дубль при синхронной работе. Это будет тоже самое, что Max(ID) + 1. Т.е. никакого смысла.
А зачем его получать до ? Плюс, ходят слухи, что таки в следующей версии генераторы появятся.


 
Fay ©   (2005-09-29 16:46) [87]

2 Курдль ©   (29.09.05 16:41) [83]
>> То ли SCOPE_IDENTITY, то ли нечто похожее!
Ни в коем случае!!


 
ANB ©   (2005-09-29 16:46) [88]


> Fay ©   (29.09.05 16:43) [85]
> 2 ANB ©   (29.09.05 16:40) [82]
> Такое "можно" называется "нельзя".
- Гы, гы. Но время от времени на форуме появляются вопросы - как это сделать.


 
Val ©   (2005-09-29 16:46) [89]

потому что не обращаются к таблице в триггере перед вставкой :)


 
Fay ©   (2005-09-29 16:47) [90]

2 ANB ©   (29.09.05 16:45) [86]
>>  в следующей версии генераторы появятся
В MSSQL 2015? 8)


 
Курдль ©   (2005-09-29 16:51) [91]


> - хоть я MS SQL и не люблю, но вот логика триггеров мне
> там больше понравилась. Во всяком случае, мутаций таблиц
> там не бывает.


Мутаций не бывает, т.к. он блокировщик, а не версионник! :)

> ANB ©   (29.09.05 16:45) [86]
> А зачем его получать до ? Плюс, ходят слухи, что таки в
> следующей версии генераторы появятся.


Я писал, зачем получать "до" в [66].
Чтобы заполнить максимум данных на клиенте, не держа при этом транзакцию открытой. Это корпоративный стандарт! Никаких "прокруток", никаких "max(ID)" и т.п. Только заранее получить, и пользовать.


 
Курдль ©   (2005-09-29 16:53) [92]


> Fay ©   (29.09.05 16:46) [87]
>
> 2 Курдль ©   (29.09.05 16:41) [83]
> >> То ли SCOPE_IDENTITY, то ли нечто похожее!
> Ни в коем случае!!


А чего тогда молчат все апологеты MS SQL? 8-()
Это ж полная Ж! :-(


 
ANB ©   (2005-09-29 16:56) [93]


> Я писал, зачем получать "до" в [66].
> Чтобы заполнить максимум данных на клиенте

Хм. Странно. Была у меня раз задачка, где я заполнял на клиенте настроечную таблицу, а потом пересылал пачку записей за одну транзакцию. Но мне не пришлось заранее доставать ID. Это некошерный подход, доставать ID до того, как юзер нажмет кнопку ОК.


 
Fay ©   (2005-09-29 16:57) [94]

2 Курдль ©   (29.09.05 16:53) [92]

Есть причины, которые позволяют мириться с некоторыми недостатками.
Пожалуй главная (но не единственная, конечно) из них - оптимизатор MSSQL (vs Oracle vs FB).


 
ANB ©   (2005-09-29 16:57) [95]


> Курдль ©   (29.09.05 16:53) [92]
- лучше не ругайся, а изучай грабли. От сумы и работы с MS SQL ни один программист не застрахован :)))


 
ANB ©   (2005-09-29 16:58) [96]


> Есть причины, которые позволяют мириться с некоторыми недостатками.
>
> Пожалуй главная (но не единственная, конечно) из них - оптимизатор
> MSSQL (vs Oracle vs FB).
???


 
Fay ©   (2005-09-29 16:59) [97]

2 ANB ©   (29.09.05 16:56) [93]
1) А почему, собственно, "до" ?
2) GUID-ы экономить не пробовали ? 8)


 
Fay ©   (2005-09-29 17:00) [98]

2 ANB ©   (29.09.05 16:58) [96]
>> ???
!!!


 
Курдль ©   (2005-09-29 17:03) [99]


> ANB ©   (29.09.05 16:57) [95]
> - лучше не ругайся, а изучай грабли. От сумы и работы с
> MS SQL ни один программист не застрахован :)))


Честно говоря, я уже второй год, как перешел в основных проектах на вижуал кролика. Так что эти проблемы совсем канули в лету. Ведь в ADO.NET о таких мелочах, как ID вообще не задумываешься: набил датасэт связанными таблицами  и сбросил в базу. Он сам разрулит, кому-что подставить.


 
kesha ©   (2005-09-29 18:25) [100]


> Курдль ©   (29.09.05 17:03) [99]


a esli sna4ala sochranil na lokal PK, a 4eres 2 dnja sbrosil v global DB


 
Fay ©   (2005-09-29 19:17) [101]

2 kesha ©   (29.09.05 18:25) [100]

Хоть через а года


 
Fay ©   (2005-09-29 19:18) [102]

B cmbIcJIE, "XOTb 4EPE3 DBA rODa" 8)


 
ANB ©   (2005-09-30 09:27) [103]


> Fay ©   (29.09.05 17:00) [98]
> 2 ANB ©   (29.09.05 16:58) [96]
> >> ???
> !!!
- чем оптимизатор MS SQL лучше ораклового ?


 
Sergey13 ©   (2005-09-30 09:31) [104]

Ну и бодягу вы тут развели. Даже для потрепаловки приличный объем.
А щас еще и холивар начнется.
8-)


 
ANB ©   (2005-09-30 10:03) [105]


> Sergey13 ©   (30.09.05 09:31) [104]
- а всего то просил посмотреть триггер.


 
Курдль ©   (2005-09-30 10:14) [106]


> kesha ©   (29.09.05 18:25) [100]
> a esli sna4ala sochranil na lokal PK, a 4eres 2 dnja sbrosil  v global DB


Я не понял, это вопрос? И в чем его суть?
Если просто держать заполненный датасэт (напоминаю - не TDataSet из Delphi, а System.Data.DataSet из ADO.NET, - для особо любознательных), который содержит в себе несколько таблиц со связанными данными, релэйшны и констрэйнты, - то ничего с ним не случится. Все "автоинкрементные" идентификаторы, внешние ключи и т.п. заполняются фиктивными данными (напр. для integer рекомендованы -1, -2, -3...). А в момент исполнения метода Update объекта DataAdapter, все они преобразуются в реальные значения из генераторов, последовательностей и т.п.

Если же Вас интересует, как сохранить данные из такого датасэта на 2 дня, чтобы потом их вставить в БД - есть метод DataSet.WriteXml(string filename);
который сохранит весть датасэт в XML, сохранив всю иерархию данных.


 
kesha ©   (2005-09-30 10:34) [107]


> Курдль ©   (30.09.05 10:14) [106]


Spasibo, potom obdumau.


 
Danilka ©   (2005-09-30 10:53) [108]

[81] Fay ©   (29.09.05 16:38)
Примеров полезности генераторов/сиквенсов не привязанных к конкретной таблице, таки да, согласен, можно найти.
Триггеры before тоже полезны бывают.
А вот именно необходимость знать значение ид таблицы до инсерта я не могу придумать.

[106] Курдль ©   (30.09.05 10:14)
То-есть, фактически ADO.NET делает то-же самое, что я написал в [67].


 
Курдль ©   (2005-09-30 11:10) [109]


> Danilka ©   (30.09.05 10:53) [108]

Не согласен по всем 3-м пунктам!

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

Если в БД хотят сделать общий идентификатор для разных таблиц, производят процесс наследования "inherit" от материнской таблицы. Если на одну запись в материнской таблице не могут ссылаться 2 записи в дочерних - взводят свойство  наследования "mutually exclusive".

Пользу получения значения ID до исполнения DML я уже неоднократно приводил - чтобы заполнять связанные таблицы и при этом не держать транзакцию открытой (это важно при многопользовательском режиме).

ADO.NET не делает то-же самое, что ты написал в [67]. Но делает это на самом низком интерфейсном уровне и гарантирует от ошибок прикладного программирования.


 
ANB ©   (2005-09-30 11:58) [110]


> Пользу получения значения ID до исполнения DML я уже неоднократно
> приводил - чтобы заполнять связанные таблицы и при этом
> не держать транзакцию открытой (это важно при многопользовательском
> режиме).
- а кто мешает заполнение связанных таблиц проводить быстро в одной транзакции, получив мастер ID после вставки ? Или вообще засунуть все это в один DML ?

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



Страницы: 1 2 3 вся ветка

Текущий архив: 2005.11.13;
Скачать: CL | DM;

Наверх




Память: 0.79 MB
Время: 0.052 c
2-1130281304
bogdan
2005-10-26 03:01
2005.11.13
создания окон нестандартной формы, delphi


14-1130150338
syte_ser78
2005-10-24 14:38
2005.11.13
время компиляции проекта


2-1130080255
TStas
2005-10-23 19:10
2005.11.13
Почему эдин программно неправильно выделятся?


2-1129558566
Dush
2005-10-17 18:16
2005.11.13
inherited


2-1130072381
tmc
2005-10-23 16:59
2005.11.13
Переменные среды Windows и TIniFile.Create