我有两个数据库,我需要确保一个数据库中的所有记录在另一个数据库中都有匹配的记录。我将这些称为 DB-SQL 和 DB-Legacy
如果两者都有 SQL 接口,这将很容易,但不幸的是,我只有这种类型的访问权限,另一个我有一个“查找记录/第一个/下一个”类型的接口。
我选择执行此任务的方法是通过以下代码将 DB-SQL 传输到客户端数据集:
var
lQuery: TADOQuery;
lProvider: TDataSetProvider;
lDataSet: TClientDataSet;
begin
lQuery := TADOQuery.Create(nil);
lProvider := TDataSetProvider.Create(nil);
lDataSet := TClientDataSet.Create(nil);
// we don't need either of these and should speed things up
lDataSet.disablecontrols;
lQuery.DisableControls;
try
lQuery.Connection := aConnection;
lQuery.SQL.Add('SELECT FieldA, FieldB, FieldC, 0 as FoundInGIS');
lQuery.SQL.Add('FROM TableA');
// following two lines needed to allow us to modify the FoundInGIS field in the clientdataset
lQuery.open;
lquery.fieldbyname('FoundInGIS').Readonly := false;
lProvider.DataSet := lQuery;
lDataSet.Data := lProvider.Data;
lDataSet.fieldbyname('FoundInGIS').readonly := false;
lDataSet.LogChanges := false;
// index by FieldA for quick searching by FindKey later
lDataSet.IndexFieldNames := 'FieldA';
finally
lQuery.Free;
lProvider.Free;
end;
这是基于http://www.podgoretsky.com/ftp/docs/Delphi/D5/dg/5_ds3.html#20536的代码
然后,这将允许我使用 First/Next 直到 EOF 迭代 DB-legacy,使用 FindKey 搜索 ClientDataSet 以确保 DB-Legacy 中的所有记录都存在于 DB-SQL 中。通过将 FoundInGIS 标记设置为 1,我可以按此值进行筛选,以查找 DB-SQL 中但 DB-Legacy 中没有的所有记录。
我的问题是我们的一个数据库比其他数据库大得多,有 3,310,510 条记录。lQuery 的记录数是正确的,但是在过程结束时 lDataSet 只有大约 2,500,000 条。
现在,我想使用 cds 来使用 FindKey 方法,TADOQuery 不支持该方法,但是如果它忽略了 1/3 的记录,它就没有多大用处了!我猜测 DataSetProvider 或 ClientDataSet 中的某处可能存在整数溢出,尽管如果是这样它不会引发异常,这有点顽皮!有没有其他人遇到过这种问题,有没有办法对其进行排序(也许通过以较小的块下载数据或使用另一种填充 CDS 的方式)?
在这种情况下,SQL-DB 是 Oracle,但代码也需要与 SQL-Server 一起使用,尽管我怀疑这是一个数据库问题。
编辑:我现在的行为略有不同。当我尝试从查询中删除一些字段时,它运行良好。所有字段都可以单独运行,但它无法处理所有字段(这支持我的溢出假设)。我现在是,但是偶尔会出现异常。例外是
'Format '%s' invalid or incompatible with argument'
这是一种误导,因为深入研究 Debug DCU 表明错误是由
SafeArrayCheck(SafeArrayCopy(VarToDataPacket(Value), FSavedPacket));
在 TCustomClientDataSet.SetData (DBClient 行 1482)。这会引发 ESafeArrayError (AResult = -2147024882),它会变成“意外的变体或安全数组错误”,但它无法处理对 FormatStr 的后续调用。