我有两个数据库,我需要确保一个数据库中的所有记录在另一个数据库中都有匹配的记录。我将它们称为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 until EOF遍历DB-legacy,使用FindKey搜索ClientDataSet,以确保DB-Legacy中的所有记录都存在于DB-SQL中。通过将FoundInGIS标记设置为1,我可以根据该值进行筛选,以查找DB-SQL中但不在DB-Legacy中的所有记录。
我的问题是,我们的一个数据库比其他数据库大得多,有3310,510条记录。lQuery具有正确的记录数量,但是在过程结束时,lDataSet只有大约2,500,000条记录。
现在,我想使用cds来利用TADOQuery中不支持的FindKey方法,但是如果它忽略了1/3的记录,那就没有多大用处了!我猜测在DataSetProvider或ClientDataSet中的某个地方可能存在整数溢出,尽管如果是这样的话它没有引发异常,这有点淘气!其他人有过这种问题吗?有没有办法对其进行排序(可能是以较小的块下载数据,或者使用另一种填充CDS的方法)?
本例中的SQL-DB是Oracle,但是代码也需要与SQL-Server一起工作,尽管我怀疑这是一个DB问题。
编辑:我现在得到了一些稍微不同的行为。当我尝试从查询中删除一些字段时,它运行得很好。所有字段都可以单独运行,但它不能处理所有字段(这支持我的溢出假设)。然而,我现在偶尔会遇到一个异常。例外情况是
'Format '%s' invalid or incompatible with argument'这具有误导性,因为深入研究Debug DCU会发现错误是由
SafeArrayCheck(SafeArrayCopy(VarToDataPacket(Value), FSavedPacket));在TCustomClientDataSet.SetData中(DBClient行1482)。这会引发一个ESafeArrayError (AResult = -2147024882),它会变成一个“意外变量或安全数组错误”,但它不能处理对FormatStr的后续调用。
发布于 2012-10-11 21:18:30
好的-在尝试了减少的字段数量后,我确信TClientDataSet不能在一个块中插入所有记录(两个字段插入所有记录,除一个字段外,所有字段插入约2900000条记录,所有字段插入250万条记录)。调用SetProvider和使用lDataSet.open也得到了相同的结果。
我已经确信问题不在lQuery或TDataSetProvider端,因为TCustomProvider.GetData在调用GetRecords之后返回了正确的记录计数。
最后,我已经能够通过将数据分成100,000个记录块来对其进行排序,如下所示:
lProvider.DataSet := lQuery;
lDataSet.SetProvider(lProvider);
lDataSet.packetrecords := 100000;
lDataSet.Open;
while lDataSet.getnextpacket > 0 do
begin
end;这似乎工作得很好,甚至给了我一个机会,如果我认为合适的话,可以将它附加到进度条上。
不过,对于VCL代码中没有出现合理的异常,我仍然不以为然。
https://stackoverflow.com/questions/12835232
复制相似问题