0

我有两个数据库,我需要确保一个数据库中的所有记录在另一个数据库中都有匹配的记录。我将这些称为 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 的后续调用。

4

1 回答 1

0

好的 - 在使用了降低的字段数量之后,我确信 TClientDataSet 无法将所有记录插入一个块中(2 个字段插入了所有记录,除了一个之外,所有记录都插入了大约 2,900,000 并且所有这些都插入了 c2,500,000)。调用 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 代码中没有引发合理的异常仍然没有给人留下深刻的印象。

于 2012-10-11T13:18:30.440 回答