-
kaif © (08.09.08 21:03) [0]Пишу приложение для базы MSSQL. Решил в приложении использовать ADO. Не могу найти хорошей статьи с примерами.
Например, у меня есть справочники.
Конструкция типа:
INSERT INTO GOODS(GOODS_NAME) VALUES(:NAME)
SELECT :ID = @@IDENTITY
у меня в ADOQuery.ExecSQL не сработала. То есть сработала, но несмотря на то, что я явно задал 2 параметра (NAME и ID), один как Dirction = pdInput, а другой - pdOutput, после ExecSQL у меня в выходном параметре присутствует NULL.
Я написал хранимую процедуру, возвращающую набор данных:CREATE PROCEDURE SP_INSERT_GOOD(@NAME VARCHAR(60))
AS
BEGIN
INSERT INTO GOODS(GOOD_NAME) VALUES(@NAME)
SELECT :ID = @@IDENTITY
END
И, используя метод ADOQuery.Open, получил желаемое.
Однако мне это решение кажется каким-то кривым.
Хотелось бы увидеть что-нибудь традиционно принятое в этой связке Delphi6-ADO-MSSQL2000.
Буду благодарен за любую информацию.
С уважением. -
INSERT INTO GOODS(GOODS_NAME) VALUES(:NAME)
SET :ID = @@IDENTITY
ADOQuery.ExecSQL -
> после ExecSQL у меня в выходном параметре присутствует NULL.
либо врешь либо ошибка в 17й строке.
stas © (08.09.08 21:08) [1]
> SET :ID = @@IDENTITY
SELECT :ID = @@IDENTITY то же самое по сути, только стиль новее. -
> ADOQuery
кстати заменил бы ты его на ADOCommand -
Медвежонок Пятачок © (08.09.08 22:08) [4]у меня в ADOQuery.ExecSQL не сработала.
ADODataSet и ADOCommand. Все остальное не использовать. -
Медвежонок Пятачок © (08.09.08 22:18) [5]TAdoCommand + 'insert into TABLENAME values(.........)'
+
TAdoDataSet + select IDENT_CURRENT('TABLENAME') -
Медвежонок Пятачок © (08.09.08 22:18) [5]
нет смысла разделять команды. опасно. а если возвращать значение через рекордсет, то тогда и инсерт тоже в TAdoDataSet перенести. -
Anatoly Podgoretsky © (08.09.08 22:34) [7]> sniknik (08.09.2008 22:27:06) [6]
О чем речь, о получение идентити?
Тогда просто insert + select в одной команде. -
Медвежонок Пятачок © (08.09.08 22:37) [8]можно и в одном. еще лучше пересесть на 2005 и заюзать output для инсерта
-
kaif © (08.09.08 22:52) [9]2 sniknik © (08.09.08 22:06) [3]
Ух ты, спасибо, я вообще не разглядел ADOCommand на палитре...
Однако все равно не работает.with ADOCommand1 do
begin
CommandText := 'INSERT INTO GOODS(GOOD_NAME) VALUES (:NAME)'#13+
'SET :ID = @@IDENTITY';
Parameters.ParamByName('NAME').Value := AName;
Execute;
ShowMessage(IntToStr(Parameters.ParamByName('ID').Value));
end;
Ошибка та же. Значение выходного параметра все равно имеет значение Null (в смысле variant).
Пробовал оба синтаксиса, и SELECT и SET. Разницы никакой. -
странно, поставь дирекшин InputOutput
-
kaif © (08.09.08 23:17) [11]stas © (08.09.08 22:56) [10]
странно, поставь дирекшин InputOutput
Давно стоит.
Если у всех это работает, буду биться с настройками, транзакциями и т.п.
я проверил, не стоит ли режим IMPLICIT_TRANSACTIONS на сервере.
select case when (@@options & 2) = 2 then 'IMPLICIT' else 'NOT IMPLICIT' end
Вроде бы не стоит.
Даже не знаю, с чем это все может быть связано. -
kaif © (08.09.08 23:35) [12]В принципе мне нравится решение Медвежонок Пятачок © (08.09.08 22:18) [5], если перевести в TAdoDataSet. Мне не очень нравится запрашивать @@IDENTITY по честному. Но это похоже на мое решение с хранимой процедурой. Неприятно то, что для того чтобы сделать инсерт я в программе вынужден делать Open. Как-то неаккуратненько.
К тому же я не люблю не разобравшись в причине брать альтернативное решение. А вдруг мне еще где-нибудь понадобится вернуть параметр?
Что я буду делать?
Вот я сделал такой запрос для исследования:with ADOCommand1 do
begin
CommandText := 'SELECT :ID = @@Error';
Execute;
ShowMessage(IntToStr(Parameters.ParamByName('ID').Value));
end;
Все отлично. Выходной параметр установлен, значение равно 0.
Значит дело в том, что у меня пакет.
Вот такой текст уже не сработал:with ADOCommand1 do
begin
CommandText := 'INSERT INTO GOODS(GOOD_NAME) VALUES (:NAME)'#13+
'SELECT :ID = @@Error';
Parameters.ParamByName('NAME').Value := AName;
Execute;
ShowMessage(IntToStr(Parameters.ParamByName('ID').Value));
end;
Причем запись вставилась, а вот второй запрос, похоже, то ли не отработал вообще, то ли не сумел донести выходной параметр до места назначения.
А вот так сработало:with ADOCommand1 do
begin
CommandText :=
'BEGIN TRAN'#13+
'INSERT INTO GOODS(GOOD_NAME) VALUES (:NAME)'#13+
'SELECT :ID = @@IDENTITY'#13+
'COMMIT TRAN';
Parameters.ParamByName('NAME').Value := AName;
Execute;
ShowMessage(IntToStr(Parameters.ParamByName('ID').Value));
end;
Буду благодарен за комментарии к этому месту. Что произошло?
И подскажите, пожалуйста, как написать так, чтобы транзакция не повисла в случае, например нарушения уникального ключа при вставке. -
> Однако все равно не работает.
в коде нет указания типа параметра, а говоришь что он pdOutput.
как знал, что врешь. -
Медвежонок Пятачок © (08.09.08 23:44) [14]у меня аналогично.
set устанавливает значение, select не устанавливает
insert into test_table(name) values('test')
set :id = @@identity -
> О чем речь, о получение идентити?
да
> Тогда просто insert + select в одной команде.
это вариант от "пятачка", а изначально попытка вернуть через параметр. оба варианта работают. если бы не 17я строка... -
> set устанавливает значение, select не устанавливает
не может быть... это разные формы одного и того же.
счас проверю. -
Медвежонок Пятачок © (08.09.08 23:50) [17]я уже раза четыре проверил.
-
Медвежонок Пятачок © (08.09.08 23:52) [18]ой нет. все работает
-
Медвежонок Пятачок © (08.09.08 23:56) [19]запрос был в дизайнтайме и после смены текста commandtext тип параметра сбрасывался в инпут