Firebird TIBQuery插入返回... INTO

时间:2011-09-27 19:36:18

标签: delphi firebird c++builder

我有一个带有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();

有什么建议吗?

10 个答案:

答案 0 :(得分:5)

来自Firebird README.returning:

  

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

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

对于DSQL,

INSERT ... RETURNING看起来与调用存储过程相同,后者返回结果集。因此,您必须使用Open代替ExecSQL

答案 1 :(得分: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 :(得分: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;

答案 3 :(得分:1)

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

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

然后可以省略你的触发器(这很好),或者修改为检测null(或者&lt; = 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;

通过以这种方式修改触发器,如果​​/当您想要插入记录块时,您可以稍后解决此问题

答案 4 :(得分:1)

IBX不是Firebird准备好的

您可以查看支持Firebird功能的FIBPLUS

  

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

答案 5 :(得分: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。< / p>

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

我也需要&#34; INSERT..RETURNING&#34;事情。 Delphi让我疯了很长时间,直到我改变了我的数据访问组件。 我甚至因此而从Delphi XE2转移到XE5 ......

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

转移到FireDAC,您将能够完成所需的一切,并且性能卓越。

答案 8 :(得分:0)

如果你有一个包含这两个字段的表: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;

答案 9 :(得分: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    火鸟3    拉撒路1.9    FPC 3.0.4 快速说明:这适用于IBX中的新Firebird API,但我没有使用IBX在Legacy Firebird API中测试它。