无法在Delphi XE8中使用MSSQL时间戳作为参数

时间:2015-08-18 14:01:16

标签: sql-server delphi sql-server-2012 delphi-xe8

我们正在将我们的一个项目从Delphi XE升级到XE8。我们的审计代码使用MSSQL(在此实例中为2012)数据库中的TIMESTAMP字段,并从表中选择使用它作为WHERE子句中的参数。

我们现在不再使用以下代码获得任何结果:

procedure TForm2.Button1Click(Sender: TObject);
begin
  ADODataset1.CommandText := 'SELECT * FROM CURRENCYAUDIT';
  ADODataset2.CommandText := 'SELECT * FROM CURRENCYAUDIT WHERE Audit_Timestamp = :Timestamp';
  ADODataset2.Parameters.Refresh;

  ADODataset1.Open;
  if ADODataset1.FieldByName('audit_timestamp').IsNull or ADODataset1.IsEmpty then
  begin
    showmessage('nothing to compare');
  end;

  ADODataset2.Parameters[0].Value := ADODataset1.FieldByName('audit_timestamp').Value;
  ADODataset2.Open;
  caption := inttostr(ADODataset2.RecordCount);
end;

其中CurrencyAudit是包含notnull timestamp audit_timestamp字段的任何旧MSSQL表。

表单的标题为0,未显示任何消息。

知道如何才能让它发挥作用吗?尝试AsString(无意义字符串,0结果),AsSQLTimestamp(参数不接受)和AsBytes(0返回)。不幸的是,.Value的返回仅仅是作为字节'变体数组的变换。这对于可视化/查看它是什么并没有帮助。

编辑:运行它.AsBytes并在调试器中查看我可以看到XE verison返回0,0,0,0,0,8,177,22而XE8返回17,32,0,0 ,0,0,0,0。检查(实际)数据库的其他字段显示记录是相同的。看起来像从DB中读取TIMESTAMPs的错误

2 个答案:

答案 0 :(得分:1)

我使用了两个AdoQueries。以下在D7中对我来说很好,在AdoQuery2中正确返回1行,但在XE8中有0个记录,因此显然有与您遇到的相同的XE8问题。

var
  S : String;
  V : Variant;
begin
  AdoQuery1.Open;
  S := AdoQuery1.FieldByName('ATimeStamp').AsString;
  V := AdoQuery1.FieldByName('ATimeStamp').AsVariant;
  Caption := S;
  AdoQuery2.Parameters.ParamByName('ATimeStamp').Value := V;
  AdoQuery2.Open;

只是为了测试,我在同一服务器表上运行我的AdoQuery1和AdoQuery2。

更新我在你的答案工作中得到了一个类似的方法,避免了对Int64ToByteArray的需求,但代价是一些稍微麻烦(效率较低)的Sql,这可能不符合你的口味。

在我的源代码AdoQuery中,我有这个Sql

select *, convert(int, atimestamp) as inttimestamp from timestamps

并在目的地

select *  from timestamps where convert(int, atimestamp) = :inttimestamp

当然可以避免在第二个AdoQuery上使用varBytes参数,因为可以获取timestamp列值的整数版本并将其分配给inttimestamp参数。

顺便说一下,原来的q

  if ADODataset1.FieldByName('audit_timestamp').IsNull or ADODataset1.IsEmpty then

这两个表达式最好用另一种方式编写。除非ADODataset1具有持久字段,否则如果它在打开时不包含任何记录,则引用audit_timestamp应该引发"字段未找到"异常。

答案 1 :(得分:0)

似乎EMBT打破了TIMESTAMP到字节数组的转换。 bytearray的XE版本是正确的,并手动将数据作为int64下拉,然后手动构建bytearray(是否有一个开箱即用的函数?)并使用它作为参数在XE8中工作。

我不知道这是否与其他二进制数据类型有类似问题。希望不是!

工作代码:

procedure TForm2.Button1Click(Sender: TObject);
var
  TestArray: TArray<Byte>;
  j: integer;
  function Int64ToByteArray(const inInt: uint64): TArray<Byte>;
  var
    i: integer;
    lInt: int64;
  begin
    SetLength(result, 8);
    lInt := inint;
    for i := low(result) to high(result) do
    begin
      result[high(result)-i] := lInt and $FF;
      lInt := lInt shr 8;
    end;

  end;

begin
  ADODataset1.CommandText := 'SELECT  *, cast(audit_timestamp as bigint) tmp FROM CURRENCYAUDIT';
  ADODataset2.CommandText := 'SELECT * FROM CURRENCYAUDIT WHERE Audit_Timestamp = :Timestamp';
  ADODataset2.Parameters.Refresh;

  ADODataset1.Open;
  if ADODataset1.FieldByName('audit_timestamp').IsNull or ADODataset1.IsEmpty then
  begin
    showmessage('nothing to compare');
  end;

  ADODataset2.Parameters[0].Value := Int64ToByteArray(ADODataset1.FieldByName('tmp').asInteger);
  ADODataset2.Open;
  caption := inttostr(ADODataset2.RecordCount);
end;

我还检查了这个在我的整个(真实)桌子上,并确保所有其他字段匹配,以确保它不是一次性的!

我会用EMBT提出一张票,让他们坐下来忽略5年; - )

https://quality.embarcadero.com/browse/RSP-11644