0

2つのデータベースがあり、一方のデータベースのすべてのレコードがもう一方のデータベースに一致するレコードを持っていることを確認する必要があります。これらを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のコードに基づいています。

これにより、EOFまでFirst / NextでDB-legacyを反復処理し、FindKeyを使用してClientDataSetを検索し、DB-LegacyのすべてのレコードがDB-SQLに存在することを確認できます。FoundInGISタグを1に設定することで、この値でフィルタリングして、DB-SQLにはあるが、DB-Legacyにはないすべてのレコードを見つけることができます。

私の問題は、私たちのデータベースの1つが他のデータベースよりも大幅に大きく、3,310,510レコードであるということです。lQueryには正しい数のレコードがありますが、プロシージャの最後では、lDataSetには約2,500,000しかありません。

ここで、CDを使用してFindKeyメソッドを使用したいと思います。これは、TADOQueryでサポートされていませんが、レコードの3分の1を無視する場合は、あまり使用されません。DataSetProviderまたはClientDataSet内のどこかに整数のオーバーフローがあるかもしれないと推測していますが、例外が発生しないのは少しやんちゃです!他の誰かがこの種の問題を抱えていましたか?それを並べ替える方法はありますか(おそらく、データを小さなチャンクにダウンロードするか、CDSにデータを取り込む別の方法を使用することによって)?

この場合のSQL-DBはOracleですが、DBの問題ではないかと思いますが、コードもSQL-Serverで動作する必要があります。

編集:私は今、いくつかのわずかに異なる動作をしています。クエリからいくつかのフィールドを削除しようとすると、正常に実行されます。すべてのフィールドは個別に正常に実行されますが、すべてを処理することはできません(これは私のオーバーフロー仮説をサポートします)。私は今ですが、時々例外が発生します。例外は

'Format '%s' invalid or incompatible with argument'

これは誤解を招く可能性があります。デバッグDCUを詳しく調べると、エラーが次の原因で発生していることがわかります。

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

TCustomClientDataSet.SetData(DBClient行1482)。これにより、ESafeArrayError(AResult = -2147024882)が発生し、「予期しないバリアントまたは安全な配列エラー」になりますが、その後のFormatStrの呼び出しを処理できません。

4

1 に答える 1

0

OK - フィールドの数をいじってみたところ、TClientDataSet はすべてのレコードを 1 つのチャンクに挿入できないことがわかりました (2 つのフィールドがすべてのレコードを挿入し、1 つを除くすべてが約 2,900,000 を挿入し、すべてが c2,500,000 を挿入しました)。SetProvider を呼び出して lDataSet.open を使用しても、同じ結果が得られました。

TCustomProvider.GetData は GetRecords を呼び出した後に正しいレコード数を返していたため、問題が lQuery または TDataSetProvider 側にあるのではないことはすでに確信していました。

最終的に、次のようにデータを 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 に答える