【问题标题】:Cannot use MSSQL Timestamp as a parameter in Delphi XE8不能在 Delphi XE8 中使用 MSSQL 时间戳作为参数
【发布时间】:2015-08-18 14:01:16
【问题描述】:

我们正在将我们的一个项目从 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 是包含非空时间戳 audit_timestamp 字段的任何旧 MSSQL 表。

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

知道如何让它工作吗?尝试过 AsString(无意义字符串,0 个结果)、AsSQLTimestamp(参数不接受)和 AsBytes(0 个返回)。不幸的是,.Value 的返回仅评估为“字节的变体数组”,这对可视化/查看它是什么没有帮助。

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

【问题讨论】:

  • 你试过.AsDateTime吗?
  • @JerryDodge TIMESTAMP 用词不当——它不是 TDateTime,它更像是一个全局 autoinc 字段。只是快速检查一下,它不起作用,因为 TBytesField 无法转换。由于 TIMESTAMP 是一个 8 字节的数字,我也尝试了 AsLargeInt,它也不起作用

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


【解决方案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 参数,因为可以获取时间戳列值的整数版本并将其分配给 inttimestamp 参数。

顺便说一句,在你原来的q中

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

这两个表达式最好反过来写。除非 ADODataset1 具有持久字段,否则如果打开时不包含任何记录,则引用 audit_timestamp 应该会引发“未找到字段”异常。

【讨论】:

  • 这在 XE8 中?仅使用 Parameter.Value := Field.AsVariant 仍然没有为我返回任何内容。后期编辑 - 是的,这只是演示代码的一个快速“演示,表明它不是由于没有数据”。生产中没有这样的东西
  • 是的,这适用于 XE。我怀疑 TField 的优化工作
  • 是的,如果我可以将其全部保留在服务器端,那似乎没问题。我认为问题是将值转换为 ByteArray - XE 与 XE8 中的数字完全不同(请参阅对 q 的编辑)。我目前的计划是尝试将其转换为 int64,然后使用它。 MSSQL 可以在 dynamicSQL 中处理它,但不能作为参数返回到原始表,因为它有类型不匹配:-/
  • 刚刚发布了一个更新,其中包含避免在 Delphi 端处理时间戳值的替代解决方法。
  • 选择你的解决方案而不是我的解决方案,因为它让微软而不是我负责处理边缘情况!对于 EMBT 方面的未来破坏/修复,也应该更有弹性。
【解决方案2】:

EMBT 似乎破坏了 TIMESTAMP 到字节数组的转换。 XE 版本的 bytearray 是正确的,可以手动将数据拉下为 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

【讨论】:

    猜你喜欢
    • 2018-12-11
    • 2023-01-09
    • 1970-01-01
    • 1970-01-01
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多