Форум: "Базы";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.31;
Скачать: [xml.tar.bz2];




Вниз

Как возвратить значение сгенерированного ID на клиента 


Наташа   (2001-12-27 09:00) [0]

Суть моей проблемы:
При занесении данных в таблицу
with IBQuery1 do
SQL.clear;
SQL.add("insert into nakl(postav_id,...) values(1,...)");
ExecSQL;
end;
IBTransaction1.Active:=true;
генерируется значение nakl_id таблицы nakl на сервере.
Я не могу получить это значение на клиенте, чтобы использовать его в дальнейшем. Вернее могу, конечно, сделав select по уникальному набору полей в этой таблице, но я думаю, что это явно не оптимальный вариант.
Может посоветуете что-нибудь?
Спасибо за внимание и понимание :)



Deniz   (2001-12-27 09:38) [1]

Хранимая процедура на сервере, возвращающая ID.
Пример:

Create procedure GetNextID
returns (ID integer) as
begin
ID = Gen_ID(GeneratorName, 1);
Suspend;
end;

Suspend вроде не обязательно (у меня в проэктах нет, но почему-то многие пишут).
Далее немного изменить код.

IBStoredProc1.StoredProcName:="GetNextID";
IBStoredProc1.Prepare;
IBStoredProc1.ExecProc;
i:=IBStoredProc1.ParamByName("ID").AsInteger;
with IBQuery1 do
SQL.clear;
SQL.add("insert into nakl(postav_id,...) values(:ID,...)");
Prepare;
ParamByName("ID").asInteger:=i;
ExecSQL;
end;



Наташа   (2001-12-27 09:42) [2]

> Deniz
Спасибо огромное!
С меня пиво :)



Deniz   (2001-12-27 10:10) [3]

Там поправочка в коде



Deniz   (2001-12-27 10:11) [4]

Там поправочка в коде
with IBQuery1 do begin
пропустил.
ЗЫ:А на счет пива - это правильно, и главное приятно.



Наташа   (2001-12-27 10:25) [5]

Всё работает, но получается, что приращение nakl_id идёт с шагом 2, а не 1, что естественно - сначала в ХП я добавляю значение генератора, а после вставки записи в таблицу генератор отрабатывает ещё один раз.
IBStoredProc1.StoredProcName:="GetNextIDNAKL";
IBStoredProc1.Prepare;
IBStoredProc1.ExecProc;
NomNakl:=IBStoredProc1.ParamByName("ID").AsInteger;

with IBQuery2 do
begin
active:=false;
SQL.clear;
SQL.Add("insert into nakl(nakl_id,textnakl,postav_id,sklad_id,firm_id)");
SQL.Add(" values(:ID,...)");
Prepare;
ParamByName("ID").asInteger:=NomNakl;
ExecSQL;
end;
Как бы всё таки сделать так, чтобы накладные шли по порядку, т.е. получать значение ID после вставки записи?



GreySerg   (2001-12-27 10:39) [6]

убери из базы триггер на вставку, где у тебя генерится значение или измени его (если там не только генерация значения)



SArthur   (2001-12-27 10:41) [7]

Можно, к примеру, выполнять вставку записи хранимой процедурой, которая возвращает dataset из одной записи и одного поля - ID.

Работаю в Sybase (ASA 6.0.3).
Обычно я даю вставку (ID автоинкрементное), а потом выбираю полученый ID вторым запросом. В некритичных местах - ничего страшного. А вот в критичных местах - пишу маленькую процедурку, которая вставляет запись и дает этот самый SELECT перед возвратом.



Slava   (2001-12-27 10:58) [8]

В триггере лучше написать примерно следующее:

IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_ID,1);



GreySerg   (2001-12-27 11:08) [9]

>Slava
Ну и как же таким способом на клиенте получить значение, чтобы использовать его в дальнейшем

По-моему вариант Deniz"а с хранимой процедурой - самый оптимальный



prosof   (2001-12-27 11:26) [10]

Так можно в хранимой процедуре не
ID = Gen_ID(GeneratorName, 1);
делать а написать
ID = Gen_ID(GeneratorName, 0);
Генератор то добавляет то чего его попросят.



Slava   (2001-12-27 11:47) [11]

> GreySerg

Это касается "убери триггер на вставку"
Не надо убирать триггер, а то вдруг кто-нибудь захочет добавить запись не из твоей программы!

А хранимая процедура - само собой.

А еще с клиента можно сделать запрос
select GEN_ID(GeneratorName, 1) from RDB$DATABASE



Наташа   (2001-12-27 11:58) [12]

Да, насчёт убрать триггер - это не серьёзно.
Сделала вставку записи в ХП.
> prosof Слушай, гениально! Так и сделаю.
> Slava Мой триггер выглядит именно так.
А select GEN_ID(GeneratorName, 1) from RDB$DATABASE
я так поняла выдаёт из системной таблицы существующее последнее
значение генератора? Побегу пробовать. Всем БОЛЬШОЕ СПАСИБО!!!

Кстати,прочитала на ib.demo.ru
"некоторые решения с применением ХП". Там такой код

record_no=gen_id(NATUR_gen, 1);
INSERT INTO NATUR (NATUR_CODE, PERSON_CODE_E) VALUES (:record_no,:masterkey);
Но он тоже прибавляет с шагом 2 или я чего-то не поняла.



Romkin   (2001-12-27 12:03) [13]

Значит, кто-то еще обращается к генератору
вариант Наташа (27.12.01 10:25) + Slava © (27.12.01 10:58)
самый оптимальный,
процедура же:
returns(ID integer)
begin
ID = Gen_ID(Natur_GEN,1);
end



Slava   (2001-12-27 12:05) [14]

http://ib.demo.ru/DevInfo/generator.htm



Наташа   (2001-12-27 12:42) [15]

Ура!Ура!Ура!
Получилось!Получилось!



Deniz   (2001-12-27 17:46) [16]

>SArthur (27.12.01 10:41)
Вопрос о вставке в хранимой процедуре интересный но ... есть несколько случаев когда это не хорошо.
Например программа с кешированием может избежать сл. проблем:
1.После вставки, необходимо сделать в программе Query.Close ... Query.Open, чтобы получить вставленную/редактированную запись.
2.Commit или Rollback делается на все таблицы в транзакции, следовательно нельзя для одной таблицы Commit а для другой Rollback.
Можно еще написать (ударение на последнюю а), но каждый для себя сам решает эти проблемы. Я сначала делал именно так (insert/edit/delete) в хранимых процедурах, но отказался.



SArthur   (2001-12-28 10:41) [17]

Обычно я так и делаю.
В смысле: вставка, запрос на ID, обновление грида (п.1 твоего письма). Такие оперции вполне можно использовать в режимах редактирования справочников. Там идет транзакция по одной, двум, редко - трем таблицам.
Там, где нужно вставить в несколько связанных таблиц, а где-нибуть что-либо апдейтнуть... Не-е-е... Там только хранимой процедурой. Во-первых, уменьшается сетевой траффик. Во вторых, эта самая процедура делает все и, в результате, ID тебе уже и не нужен. В третьих, программный код более читабельный:
var tq: TQuery;
Begin
...
tq:=TQuery.Create(nil);
try
tq.DatabaseName:="myDB_alias";
tq.SQL.Add("CALL MyBigInsert_Update_Proc(:prm1, :prm2)");
tq.ParamByName("prm1").AsInteger:=1;
tq.ParamByName("prm2").AsString :="text";
DataModule1.Database1.StartTransaction;
try
tq.ExecSQL; // или tq.Open, ежели есть результат
DataModule1.Database1.Commit;
except
On E: Exception do begin
DataModule1.Database1.Rollback;
// <error handler code>
end;
end;
finally
tq.Free;
end;
...
End;


Примерно так. И с BDE и с ADO работает.
Реализация MyBigInsert_Update_Proc напрямую зависит от используемого DB сервера.

Ну, это, поругайте код, что ли... :-)))




Форум: "Базы";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.01.31;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.76 MB
Время: 0.024 c
1-99993           Сергей Н.             2002-01-12 15:58  2002.01.31  
Перекодировка


14-100055         VEG                   2001-12-10 22:01  2002.01.31  
Нужен компонент типа LABEL, только с большей скоростью перерисовки!!!


4-100129          -Coban-               2001-12-01 16:45  2002.01.31  
Перехват ссылок IE


3-99895           sergeyh@ukrref.uz.go  2001-12-28 12:02  2002.01.31  
Присечение подбора пароля SysDBA


1-100007          f0rm                  2002-01-14 16:23  2002.01.31  
ListView sort