Firebird TIBQuery插入返回... INTO

问题描述 投票:3回答:10

我有一个带有Generator的firebird 2.x数据库和一个生成关键字段的触发器。我需要从下面的查询中获取返回的值。

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

我尝试了以下代码的几个版本,但它不起作用,我得到

动态sql错误sql错误代码= -104

是否真的可以使用TIBQuery在delphi中获取返回值?

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();

有什么建议?

delphi firebird c++builder
10个回答
5
投票

来自Firebird README.returning:

INTO部分(即变量列表)仅在PSQL中允许(分配局部变量)并在DSQL中被拒绝。

由于IBX使用DSQL,您应该从查询中排除INTO部分。

用于DSQL的INSERT ... RETURNING看起来与调用存储过程相同,后者返回结果集。所以,你必须使用Open而不是ExecSQL


0
投票

从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 Firebird 3 Lazarus 1.9 FPC 3.0.4快速注释:这适用于IBX中的新Firebird API,但我没有使用IBX在Legacy Firebird API中测试它。


3
投票

将动态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
投票

使用Delphi 6我使用EXECUTE BLOCK语句成功返回ID:

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
投票

IBX不是Firebird准备好的

你可以看看支持Firebird功能的FIBPLUS

FIBPlus还支持FB2.0插入......进入...返回。现在你不应该费心从客户端获取生成器值,而是将它们保留在触发器中。您还可以使用RDB $ DB_KEY。插入返回和RDB $ DB_KEY的新工作变体显示在示例“FB2InsertReturning”中。


1
投票

为什么不首先获得VoucherNo的下一个值,然后是

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

?

然后可以省略您的触发器(这很好),或者修改以检测null(或<= 0也可以是有用的),然后只填充vno字段。

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;

通过以这种方式修改触发器,如果​​/当您想要插入记录块时,可以在以后节省您的头痛


1
投票

我想知道INSERT是否可以包装成EXECUTE BLOCK命令。那么IBX会管理EXECUTE BLOCK吗?

希望在XE2中的IBX和Unified Interbase中尝试它

PS:即使它没有,我找到了这个库,告诉你在Delphi XE2的IBX(x86和x64)上工作并添加EXECUTE BLOCK支持:http://www.loginovprojects.ru/index.php?page=ibxfbutils#eb


0
投票

据我所知,IBX应该有一些变化。内部INSERT ... RETURNING的处理方式与返回参数的可选程序相同。


0
投票

我知道很久以前就回答了这个问题,但我必须尽可能清楚地写出这个问题,对于那些需要我的人来说。

我也需要“INSERT..RETURNING”的东西。 Delphi让我疯了很长时间,直到我改变了我的数据访问组件。我甚至因此而从Delphi XE2转移到XE5 ......

结论:IBX不支持退货! FireDAC对于我需要的Firebird来说是完美的。

只需转移到FireDAC,您就可以完成所需的一切,并且性能卓越。


0
投票

如果你有一个包含这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;
© www.soinside.com 2019 - 2024. All rights reserved.