0

데이터베이스가 두 개인 경우 하나의 데이터베이스에있는 모든 레코드가 다른 레코드와 일치하는지 확인해야합니다. 나는이 DB-SQL과 DB-Legacy를 호출 할 것이다.TADOQuery에서 부분적으로 만 데이터를 전송하는 ClientDataSet

이것은 둘 다 SQL 인터페이스를 가지고 있으면 충분하지만 불행히도이 유형의 액세스는 하나 밖에 없다. 다른 레코드는 'find record/first/다음 '유형 인터페이스.

나는이 작업을 수행하기 위해 선택한 방법은 아래의 코드를 통해 ClientDataSet에에 DB-SQL을 전송하는 것입니다

: 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; 

이이 코드를 기반으로이 후 수 DB-Legacy의 모든 레코드가 DB-SQL에 있는지 확인하기 위해 FindKey를 사용하여 ClientDataSet을 검색하여 EOF까지 First/Next로 DB-legacy를 반복합니다. FoundInGIS 태그를 1로 설정하면이 값으로 필터링하여 DB-SQL에는 있지만 DB-Legacy에는없는 모든 레코드를 찾을 수 있습니다.

제 문제는 데이터베이스 중 하나가 다른 데이터베이스보다 3,310,510 개 큰 레코드입니다. lQuery는 정확한 레코드 수를 갖지만 프로 시저가 끝나면 lDataSet 만 약 2,500,000 개입니다.

이제 TDSOQuery에서 지원되지 않는 FindKey 메서드를 사용하기 위해 CD를 사용하고 싶지만 레코드의 1/3을 무시하면별로 유용하지 않습니다! DataSetProvider 또는 ClientDataSet의 어딘가에 정수 오버플로가있을 수 있다고 추측합니다. 그렇다면 예외가 발생하지 않는 것은 조금 장난입니다. 다른 사람이 이런 종류의 문제가 있었는지, 그것을 정렬하는 방법이 있습니까 (아마도 작은 단위로 데이터를 다운로드하거나 CDS를 채우는 다른 방법을 사용하여)?

이 경우 SQL-DB는 Oracle이지만 코드는 SQL Server와 함께 작동해야하지만 DB 문제는 아닙니다.

편집 : 이제 약간 다른 동작이 나타납니다. 쿼리에서 일부 필드를 제거하려고하면 정상적으로 실행됩니다. 모든 필드는 개별적으로 OK를 실행하지만 모든 오버플로 가설을 지원하는 모든 필드를 처리 할 수는 없습니다. 지금은 예외적 인 경우가 종종 있습니다. 예외는 디버그 DCUs을 탐구하기로 오류에 TCustomClientDataSet.SetData

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

(DBClient 라인 1482)에 의해 발생되는 표시,

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

이 잘못이다. 이로 인해 '예상치 못한 변형 또는 안전한 배열 오류'가되는 ESafeArrayError (AResult = -2147024882)가 발생하지만 후속 FormatStr 호출을 처리 할 수 ​​없습니다.

+0

제 문제는 데이터베이스 중 하나가 다른 데이터베이스보다 3,310,510 개 큰 레코드입니다. lQuery는 정확한 레코드 수를 갖지만 프로 시저가 끝나면 lDataSet 만 약 2,500,000 개입니다. - 원래 데이터 집합에 새로운 데이터 집합에 삽입되지 않은 중복 레코드가있을 수 있습니까? –

+0

그렇다면 원래의 lQuery로 옮겨서는 안됩니다. 내가 어쨌든 지금 고칠 수 있다고 생각해. –

답변

0

OK - TClientDataSet이 모든 레코드를 하나의 청크에 삽입 할 수 없다는 확신을 갖게되었습니다. (2 개의 필드가 모든 레코드를 삽입했지만 모두 하나는 약 2,900,000 개를 삽입했으며 모두 모두 250,000을 삽입했습니다.). SetProvider를 호출하고 lDataSet.open을 사용하여 동일한 결과가 발생했습니다.

나는 TCustomProvider.GetData가 GetRecords를 호출 한 후 올바른 recordcount를 반환 했으므로 문제가 lQuery 또는 TDataSetProvider 측에 없다고 이미 확신했습니다.

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

이 잘 작동하는 표시, 심지어 나에게에 첨부 할 수있는 기회를 제공합니다 다음과 같이

결국

나는 10 만 개 기록 덩어리로 데이터를 분할하여 분류 할 수 있었다 진행률 표시 줄이 맞으면 나타납니다.

그래도 VCL 코드에서 의미있는 예외가 발생하지 않았다는 사실에 깊은 인상을 받았다.