如何在Delphi 10中使用SQLite获取最后插入记录的ID?

5

Delphi 10 配合 Firemonkey 和 SQLite:在运行下面的代码之后,我想获取插入到 SQLite 表中的最后一条记录的 ID。我该如何获得最后一个 ID?

注意:Table 1 的 ID 字段是自增的。

var myQr: TFDQuery;
begin

   myQr := TFDQuery.Create(Self);

   with myQr do begin
      SQL.Add('Insert into table1 values (:_id, :_name, :_dthr)');
      Params.ParamByName('_id').ParamType := TParamType.ptInput;
      Params.ParamByName('_id').DataType  := TFieldType.ftInteger;
      Params.ParamByName('_id').Value     := null;

      ParamByName('_name').AsString       := 'name test';
      ParamByName('_dthr').AsDateTime     := Now;
      ExecSQL;
   end;

   // How to get last ID?  <<<<<<<<<<<<<=================

   myQr.DisposeOf;

你可以运行一个单独的查询 select top 1 _id from table1 order by 1 desc,但我建议使用 select 语句,打开查询,使用 append,然后在发布后简单地读取 ID。特别是因为从插入此时到运行第二个查询的时间,很有可能另一个客户端已经在这段时间内插入了其他内容,所以必须添加事务模式。长话短说,不要执行“Insert”语句。相反,打开“Select”语句,使用“Append”和“Post”。 - Jerry Dodge
@JerryDodge,在发布我的问题之前,我尝试使用append但无法使用参数使其正常工作。我知道使用参数可以使系统更安全,例如防止SQL注入攻击。使用append是否可以继续使用我在SQL语句中指定的parameters?如何实现? - Zayn Barcktu
如果我没记错的话,使用Append并将值传递到每个字段内部会使用参数,或者至少,从本质上讲应该可以防止SQL注入。换句话说,在使用Append方法时不需要使用参数。 - Jerry Dodge
2
基本上就像 Q.SQL.Text := 'select * from ThisTable'; Q.Open; Q.Append; Q.FieldByName('MyField').AsString := 'Some Value'; Q.Post; NewID := Q.FieldByName('ID').AsInteger; 这样,至少我在ADO中是这样做的,但FireDac应该几乎没有什么不同。 - Jerry Dodge
好的。感谢您的帮助! - Zayn Barcktu
1个回答

9

如果您的ID列被声明为INTEGER PRIMARY KEY,则可以查询last_insert_rowid。在这种情况下,该列成为ROWID的别名。如果是这种情况,您可以使用本地查询方式进行查询,例如:

uses
  FireDAC.Phys.SQLiteWrapper;

function GetLastInsertRowID(Connection: TFDConnection): Int64;
begin
  Result := Int64((TObject(Connection.CliObj) as TSQLiteDatabase).LastInsertRowid);
end;

或者通常的方法是调用GetLastAutoGenValue方法:

function GetLastInsertRowID(Connection: TFDConnection): Int64;
begin
  Result := Int64(Connection.GetLastAutoGenValue(''));
end;

@JerryDodge的评论是关于另一个用户在一次交易和另一次交易之间插入新记录会在这种情况下出现问题吗? - Zayn Barcktu
1
不是这样的。在数据库连接成功后,它返回最后记录的ROWID。实际上,它被实现为一个名为lastRowid的单个会话属性。你甚至可以手动更改该值。 - Victoria
不,那并不适用。它是每个连接属性。只有在您使用另一个线程的相同连接插入元组时,才可能获得不正确的值。 - Victoria
1
@ZaynBarcktu:维多利亚的方式绝对是做这件事的方法。 - MartynA
@ZaynBarcktu,我的最初评论是关于运行单独的查询存在另一个条目的风险。因此,只有使用我的第一种方法准确地完成它需要事务模式。然而,这似乎是一个非常好的方法来做到这一点,并且它似乎是为您的确切目的而设计的。 - Jerry Dodge
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接