Delphi ClientDataSet仅从TADOQuery部分传输数据

Delphi ClientDataSet仅从TADOQuery部分传输数据,delphi,delphi-2006,tclientdataset,tadoquery,tdatasetprovider,Delphi,Delphi 2006,Tclientdataset,Tadoquery,Tdatasetprovider,我有两个数据库,我需要确保一个数据库中的所有记录在另一个数据库中都有匹配的记录。我将这些称为DB-SQL和DB Legacy 如果两者都有一个SQL接口,这就足够容易了,但不幸的是,我只能访问其中一个,而另一个我有一个“find record/first/next”类型的接口 我选择的执行此任务的方法是通过以下代码将DB-SQL传输到clientdataset: var lQuery: TADOQuery; lProvider: TDataSetProvider; l

我有两个数据库,我需要确保一个数据库中的所有记录在另一个数据库中都有匹配的记录。我将这些称为DB-SQL和DB Legacy

如果两者都有一个SQL接口,这就足够容易了,但不幸的是,我只能访问其中一个,而另一个我有一个“find record/first/next”类型的接口

我选择的执行此任务的方法是通过以下代码将DB-SQL传输到clientdataset:

  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;
这是基于

这将允许我使用First/Next迭代DB legacy直到EOF,使用FindKey搜索ClientDataSet以确保DB legacy中的所有记录都存在于DB-SQL中。通过将FoundInGIS标记设置为1,我可以根据该值进行筛选,以查找DB-SQL中但不在DB Legacy中的所有记录


我的问题是,我们的一个数据库比其他数据库大得多,有3310510条记录。lQuery具有正确的记录数,但在过程结束时,lDataSet只有大约2500000条记录

现在,我想使用CD来使用FindKey方法,这在TADOQuery中不受支持,但是如果它忽略了1/3的记录,它就没有多大用处了!我猜DataSetProvider或ClientDataSet中可能存在整数溢出,尽管如果是这样,它不会引发异常,这有点淘气!有没有其他人遇到过这种问题,有没有办法对其进行排序(可能是通过下载小块数据或使用另一种填充CD的方式)

本例中的SQL-DB是Oracle,但代码也需要与SQL Server一起工作,尽管我怀疑这是一个DB问题

编辑: 我现在有了一些稍微不同的行为。当我尝试从查询中删除一些字段时,它运行良好。所有字段单独运行正常,但它无法处理所有字段(这支持我的溢出假设)。不过,我现在偶尔会遇到一个例外。例外是

'Format '%s' invalid or incompatible with argument'
这是误导性的,因为深入研究调试DCU表明错误是由

SafeArrayCheck(SafeArrayCopy(VarToDataPacket(Value), FSavedPacket));

在TCustomClientDataSet.SetData中(DBClient第1482行)。这将引发一个ESafeArrayError(AResult=-2147024882),它将成为“意外的变体或安全数组错误”,但它无法处理对FormatStr的后续调用。

OK-在处理了带下来的字段数后,我确信TClientDataSet无法将所有记录插入一个块中(2个字段插入了所有记录,除了一个字段外,其他字段都插入了大约2900000条记录,所有字段都插入了C2500000条记录)。调用SetProvider并使用lDataSet.open也得到了相同的结果

我已经确信问题不在lQuery或TDataSetProvider端,因为TCustomProvider.GetData在调用GetRecords后返回了正确的recordcount

最后,我将数据分成100000个记录块,如下所示:

  lProvider.DataSet := lQuery;
  lDataSet.SetProvider(lProvider);
  lDataSet.packetrecords := 100000;
  lDataSet.Open;
  while lDataSet.getnextpacket > 0 do
  begin
  end;
这似乎工作得很好,甚至给了我一个机会,如果我认为合适的话,可以将其附加到进度条上


尽管VCL代码中没有出现合理的异常,但仍然没有给人留下深刻印象。

我的问题是,我们的一个数据库比其他数据库大得多,有3310510条记录。lQuery有正确的记录数,但是在过程结束时,lDataSet只有2500000条左右。-是否有重复的记录在原始数据集中,没有被插入到新数据集中?如果有,那么它肯定不应该被带到原始lQuery中?无论如何,我想我现在已经修复了它。