ClientDataSet仅部分从TADOQuery传输数据

时间:2012-10-11 08:24:22

标签: delphi delphi-2006 tclientdataset tadoquery tdatasetprovider

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

如果两个都有一个SQL接口,这很容易,但不幸的是我只有这种类型的访问权限,另一个我有一个'查找记录/第一个/下一个'类型接口。

我选择执行此任务的方法是通过以下代码将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;

这是基于http://www.podgoretsky.com/ftp/docs/Delphi/D5/dg/5_ds3.html#20536

的代码

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

我的问题是我们的一个数据库比其他数据库大得多,达到3,310,510条记录。 lQuery具有正确的记录数,但是在过程结束时,lDataSet只有大约2,500,000个。

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

在这种情况下,SQL-DB是Oracle,但代码也需要与SQL-Server一起使用,但我怀疑这是一个数据库问题。

编辑: 我现在的行为略有不同。当我尝试从查询中删除一些字段时,它运行正常。所有字段都单独运行,但它无法处理所有字段(支持我的溢出假设)。我现在,但偶尔会被提出异常。

是个例外
'Format '%s' invalid or incompatible with argument'

这是误导性的,因为深入调试DCU显示错误是由

引发的
SafeArrayCheck(SafeArrayCopy(VarToDataPacket(Value), FSavedPacket));
TCustomClientDataSet.SetData中的

(DBClient行1482)。这会引发一个ESafeArrayError(AResult = -2147024882),它会变成'意外变种或安全数组错误',但它无法处理对FormatStr的后续调用。

1 个答案:

答案 0 :(得分: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代码中没有引起明显的异常,仍然没有留下深刻的印象。