无法在 Delphi XE8 中使用 MSSQL 时间戳作为参数
Cannot use MSSQL Timestamp as a parameter in Delphi XE8
我们正在将我们的一个项目从 Delphi XE 升级到 XE8。我们的审计代码使用 MSSQL(在本例中为 2012)数据库中的 TIMESTAMP 字段,并从 table 中选择,并将其用作 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 table。
表单的标题为 0,未显示任何消息。
知道如何让它工作吗?尝试了 AsString(无意义的字符串,0 个结果)、AsSQLTimestamp(参数不接受)和 AsBytes(0 return)。不幸的是,.Value
的 return 仅评估为 'variant array of byte',这对 visualise/see 它是什么没有帮助。
编辑:运行 它作为 .AsBytes 并在调试器中查看,我可以看到 XE verison returning 0,0,0,0,0,8,177,22 而XE8 returning 17,32,0,0,0,0,0,0。检查(真实)数据库的其他字段显示记录是相同的。看起来像是从 DB
读取 TIMESTAMP 时的错误
我正在使用两个 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 针对同一台服务器 table。
更新: 我有一个与你的答案中的方法类似的方法,它避免了对 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 应该引发 "Field not found" 异常。
似乎 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;
我还检查了我的整个(真实)table 并确保所有其他字段匹配以确保它不是一次性的!
我会用 EMBT 开张罚单让他们坐视不管 5 年;-)
我们正在将我们的一个项目从 Delphi XE 升级到 XE8。我们的审计代码使用 MSSQL(在本例中为 2012)数据库中的 TIMESTAMP 字段,并从 table 中选择,并将其用作 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 table。
表单的标题为 0,未显示任何消息。
知道如何让它工作吗?尝试了 AsString(无意义的字符串,0 个结果)、AsSQLTimestamp(参数不接受)和 AsBytes(0 return)。不幸的是,.Value
的 return 仅评估为 'variant array of byte',这对 visualise/see 它是什么没有帮助。
编辑:运行 它作为 .AsBytes 并在调试器中查看,我可以看到 XE verison returning 0,0,0,0,0,8,177,22 而XE8 returning 17,32,0,0,0,0,0,0。检查(真实)数据库的其他字段显示记录是相同的。看起来像是从 DB
读取 TIMESTAMP 时的错误我正在使用两个 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 针对同一台服务器 table。
更新: 我有一个与你的答案中的方法类似的方法,它避免了对 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 应该引发 "Field not found" 异常。
似乎 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;
我还检查了我的整个(真实)table 并确保所有其他字段匹配以确保它不是一次性的!
我会用 EMBT 开张罚单让他们坐视不管 5 年;-)