Firebird TIBQuery вставка с возвратом ... INTO - PullRequest
3 голосов
/ 27 сентября 2011

У меня есть база данных Firebird 2.x с Генератором и триггером для генерации ключевого поля. Мне нужно получить возвращенное значение из запроса ниже.

INSERT INTO XXXX (vdate,description) values ('"+ VDate +"','"+ Description +"') returning vno INTO :ParamVoucherNo

Я попробовал несколько версий приведенного ниже кода, но он не заработал, и я получил

Динамическая ошибка SQL Ошибка кода SQL = -104

Действительно ли возможно получить возвращаемое значение в Delphi, используя TIBQuery?

Query1->SQL->Clear();
Query1->SQL->Add("INSERT INTO XXXX (vodate,description) values ('"+ VDate +"','"+ Description +"') returning vno INTO :ParamVoucherNo");

Query1->Params->ParamByName("ParamVoucherno")->ParamType = ptResult;
Query1->Params->ParamByName("ParamVoucherno")->DataType = ftInteger;
Query1->Params->ParamByName("ParamVoucherno")->Value = "";
Query1->Prepare();
Query1->ExecSQL();

Есть предложения?

Ответы [ 10 ]

5 голосов
/ 28 сентября 2011

От Firebird README. Возврат:

Часть INTO (т.е. список переменных) разрешена только в PSQL (для назначить локальные переменные) и отклонить в DSQL.

Поскольку IBX использует DSQL, вы должны исключить INTO часть из вашего запроса.

INSERT ... RETURNING для DSQL выглядит так же, как вызов хранимой процедуры, которая возвращает набор результатов. Таким образом, вы должны использовать Open вместо ExecSQL.

3 голосов
/ 28 сентября 2011

Ваше смешивание динамического SQL с параметрами просто сбивает с толку.

Сделайте это вместо:

Query1->SQL->Clear();
Query1->SQL->Add("INSERT INTO table1 (vodate,description) VALUES"+
                 "(:VoDate,:Description) RETURNING vno INTO :VoucherNo ");
Query1->Params->ParamByName("VoDate")->Value = VDate;
Query1->Params->ParamByName("description")->Value = Description;

Query1->Prepare();
Query1->ExecSQL();
VoucherNo = Query1->Params->ParamByName("VoucherNo")->AsInteger;
2 голосов
/ 28 августа 2012

Использование Delphi 6 У меня есть идентификатор, успешно возвращаемый с помощью инструкции EXECUTE BLOCK:

EXECUTE BLOCK
RETURNS ( DeptKey INT )
AS
BEGIN
  INSERT INTO DEPARTMENT 
      ( COMPANY_KEY, DEPARTMENT_NAME ) 
      VALUES ( 1, 'TEST1' ) RETURNING DEPARTMENT_KEY INTO :DeptKey;
  SUSPEND;
END;

Из Delphi вы можете сделать следующее:

FQuery.SQL.Text := '<Execute Block Statement>';
FQuery.Open();
ANewKey := FQuery.Fields[0].AsInteger;
1 голос
/ 27 августа 2012

Интересно, можно ли включить INSERT в команду EXECUTE BLOCK.Будет ли IBX управлять EXECUTE BLOCK тогда?

Надеюсь попробовать его в IBX и UnifiedInterbase в XE2

PS: Даже если этого не произойдет, я обнаружил библиотеку, которая говорит работать поверх IBX Delphi XE2 (как x86, так и x64) и добавить поддержку EXECUTE BLOCK:http://www.loginovprojects.ru/index.php?page=ibxfbutils#eb.

1 голос
/ 28 сентября 2011

IBX не готов к Firebird

Вы можете взглянуть на FIBPLUS , которые поддерживают функции Firebird

FIBPlus также поддерживает вставку FB2.0 ... в ... возврат. Теперь ваша очередь не должен беспокоиться о получении значений генератора от клиента, но оставь их в курке. Вы также можете использовать RDB $ DB_KEY. Новое возможно варианты работы с возвратом вставки и RDB $ DB_KEY показаны в пример «FB2InsertReturning».

1 голос
/ 28 сентября 2011

Почему бы сначала не получить следующее значение для VoucherNo, а затем

"INSERT INTO table1 (vno, vodate,description) VALUES (:VoucherNo,:VoDate,:Description)");

Ваш триггер может быть либо обойден (что неплохо), либо изменен для обнаружения нуля (или <= ноль тоже может быть полезным) и только после этого заполняет поле vno. </p>

create trigger bi_mytable
  active before insert position 1
  on mytable
as
begin
  if (new.vno is null)
    then new.vno = next value for gen_VoucherNos;
end

На стороне клиента вы можете:

select gen_id(gen_VoucherNos, 1) from rdb$database;

Изменяя триггер таким образом, вы избавляете себя от головной боли позже, если / когда вы хотите вставить блоки записей

0 голосов
/ 20 декабря 2017

Из источников IBx2 вы можете сделать это так:

//Uses IBSql;
//var   Cur: IResults;
  IBSQL1.SQL.Text := 'delete from tbl_document where id = 120 returning id;';
  IBSQL1.Prepare;
  if IBSQL1.Prepared then
  begin
    Cur := IBSQL1.Statement.Execute(IBTransaction1.TransactionIntf);
    WriteLn(Cur.Data[cou].AsString);
    Cur.GetTransaction.Commit(True);
  end;

Код интерфейса IResults:

  IResults = interface
   function getCount: integer;
   function GetTransaction: ITransaction;
   function ByName(Idx: String): ISQLData;
   function getSQLData(index: integer): ISQLData;
   procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PChar);
   procedure SetRetainInterfaces(aValue: boolean);
   property Data[index: integer]: ISQLData read getSQLData; default;
   property Count: integer read getCount;
  end;

Тестовая среда: Arch Linux X86 Жар-птица 3 Лазарь 1.9 FPC 3.0.4 Краткое примечание: это работает на новом Firebird API в IBX, но я не тестировал его в Legacy Firebird API с IBX.

0 голосов
/ 11 мая 2016

Если у вас есть таблица с этими 2 полями: GRP_NO и GROUPNAME и вы хотите получить новый GRP_NO, вы должны использовать RET_ в качестве префикса, см. Пример:

procedure TFormDatenbank.Button1Click(Sender: TObject);
var
  q: Uni.TUniQuery;
  ID: Integer;
  GroupName: String;
begin
  GroupName := 'MyGroupName';

  q := TUniQuery.Create(nil);
  try
    q.Connection := Datenmodul.UniConnection;
    q.ParamCheck := true; // the default value of ParamCheck is true.
    q.SQL.Clear;
    q.SQL.Add('SELECT GRP_NO, GROUPNAME FROM GROUPDATA WHERE GROUPNAME = :GROUPNAME');
    q.ParamByName('GROUPNAME').AsString := GroupName;
    q.Open;

    if q.RecordCount > 0 then
      ID := q.FieldByName('GRP_NO').AsInteger
    else
    begin
      // there exist no group with this name, so insert this new name
      q.SQL.Clear;
      q.SQL.Add('INSERT INTO GROUPDATA');
      q.SQL.Add('(GROUPNAME)');
      q.SQL.Add('VALUES');
      q.SQL.Add('(:GROUPNAME)');
      q.SQL.Add('RETURNING GRP_NO;');

      q.ParamByName('GROUPNAME').AsString := GroupName;
      q.Execute;
      ID := q.ParamByName('RET_GRP_NO').AsInteger;
    end;
  finally
    q.Free;
  end;
end;
0 голосов
/ 04 августа 2015

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

Мне тоже нужна была вещь "INSERT..RETURNING". Delphi долго сводил меня с ума, пока я не сменил компоненты доступа к данным. я даже перешел с Delphi XE2 на XE5 только из-за этого ...

вывод: IBX НЕ поддерживает ВОЗВРАТ! FireDAC идеально подходит для Firebird.

просто перейдите на FireDAC, и вы сможете делать все, что вам нужно, и с высокой производительностью.

0 голосов
/ 28 сентября 2011

Как я знаю, в IBX должны быть внесены некоторые изменения.Внутренне INSERT ... RETURNING следует обрабатывать так же, как выбираемую процедуру с возвращаемыми параметрами.

...