0

我有兩個數據庫,我需要確保一個數據庫中的所有記錄在另一個數據庫中有匹配的記錄。我將這些稱爲DB-SQL和DB-LegacyClientDataSet只部分從TADOQuery傳輸數據

如果兩者都有SQL接口,這很容易,但不幸的是我只有這種類型的訪問權限,另一個我有'find record/first /下一個'類型的界面。

我所選擇來執行此任務的方法是將DB-SQL通過下面的代碼傳送到ClientDataSet的:在http://www.podgoretsky.com/ftp/docs/Delphi/D5/dg/5_ds3.html#20536

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中的所有記錄。

我的問題是我們的一個數據庫比其他數據庫大得多,總數爲3,310,510條記錄。 lQuery具有正確的記錄數,但是在過程結束時,lDataSet只有大約2,500,000個記錄。

現在,我想使用CD來使用FindKey方法,這在TADOQuery中不受支持,但是如果它忽略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的後續調用。

+0

我的問題是我們的一個數據庫比其他數據庫大得多,在3,310,510條記錄上。 lQuery具有正確的記錄數,但是在過程結束時,lDataSet只有大約2,500,000個記錄。 - 原始數據集中是否存在沒有插入新數據集的重複記錄? –

+0

如果有的話肯定不應該被放入原始的lQuery中?無論如何,我認爲我現在已經修好了。 –

回答

0

確定 - 在播放了多少個字段後,我確信TClientDataSet無法在一個塊中插入所有記錄(2個字段插入了所有記錄,除1個插入了大約2,900,000個並且所有記錄都插入了c2,500,000 )。通過調用SetProvider和使用lDataSet.open來獲得相同的結果。

我已經確信自己這個問題不在lQuery或TDataSetProvider端,因爲TCustomProvider.GetData在調用GetRecords之後返回了正確的記錄計數。

最後,我已經能夠通過拆分數據梳理出來爲10萬的記錄塊如下:

lProvider.DataSet := lQuery; 
    lDataSet.SetProvider(lProvider); 
    lDataSet.packetrecords := 100000; 
    lDataSet.Open; 
    while lDataSet.getnextpacket > 0 do 
    begin 
    end; 

這似乎做工精細,甚至給了我一個機會,將其附加到進度條,如果我覺得合適。儘管如此,在VCL代碼中沒有提出明智的例外,但仍然沒有留下深刻印象。