2012-10-04 1 views
4

링크 된 목록별로 그룹화 된 요소가있는 테이블을 받았는데이를 처리하는 데 어려움이 있습니다.Access 2007 연결된 목록별로 그룹화 할 쿼리/vba를 향상 시키십시오.

이 함수는 찾기 만하지만 작업 스케줄러 이후 실행되거나 메모리 문제가있을 때 매크로가 어디에 있는지 묻는 경우가 자주 있습니다.

idGroup (영어로 번역 됨)을 찾으려면 다음 코드를 사용하고 30 000 행 및 약 2500 그룹에 대해 시간이 걸리기 때문에 속도를 향상시킬 수있는 방법이 있는지 궁금합니다. (내가 진행 상황을보고 VBA를 사용했던 이유는 ...입니다)

'Simple example 
'idGroup,id2,id1 
'6338546,14322882,13608969 
'6338546,13608969,13255363 
'6338546,6338546,14322882 
'6338546,11837926,11316332 
'6338546,12297571,11837926 
'6338546,13255363,12811071 
'6338546,12811071,12297571 
'6338546,7610194,7343817 
'6338546,7935943,7610194 
'6338546,8531387,7935943 
'6338546,6944491,6611041 
'6338546,7343817,6944491 
'6338546,9968746,9632204 
'6338546,10381694,9968746 
'6338546,6611041,0 
'6338546,8920224,8531387 
'6338546,9632204,8920224 
'6338546,11316332,10941093 
'6338546,10941093,10381694 


Public Function GetidGroup() 
    'first id1 is always 0 
    sql = "SELECT idGroup, id2, id1 FROM TABLE_WITH_LINKED_LIST WHERE id1='0' ORDER BY id2 DESC" 
    Dim rs As Recordset 
    Dim uidLikedList As String, id2 As String, id1 As String 

    Set rs = CurrentDb.OpenRecordset(sql) 
    Dim total As Long 
    Dim idGroup As String 
    Dim incrément As Long, progress As Double 

    total = rs.RecordCount 
    incrément = 1 

    While Not rs.EOF 
     progress = Math.Round(100 * incrément/total, 2) 

     'Print in order to avoir freezing 
     Debug.Print progress 

     If rs.Fields("idGroup") = "" Then 
      id2 = rs.Fields("id2") 

      idGroup = precedentUid(id2) 

      rs.Edit 
      rs.Fields("idGroup") = idGroup 
      rs.Update 
     End If 

     incrément = incrément + 1 
     rs.MoveNext 
    Wend 

    rs.Close 
    Set rs = Nothing 
    GetidGroup = total 
End Function 

'Recursive function 
'Deepest so far is about 62 calls 
Public Function precedentUid(id2 As String) As String 
    sql = "SELECT idGroup, id2 FROM TABLE_WITH_LINKED_LIST WHERE id1 = '" & id2 & "'" 
    Dim rs As Recordset 
    Dim precedentid2 As String 
    Dim idGroup As String 
    Dim ret As String 

    Set rs = CurrentDb.OpenRecordset(sql) 
    If rs.EOF Then 
     rs.Close 
     Set rs = Nothing 
     precedentUid = id2 
    Else 
     'Some records have several references 
     '56 impacted records : 
     'TODO : Give the min id2 to the group 
     ret = "-1" 
     While Not rs.EOF   
      If rs.Fields("idGroup") = "" Then 
       precedentid2 = rs.Fields("id2") 
       idGroup = precedentUid(precedentid2) 

       If ret = "-1" Or CLng(ret) > CLng(idGroup) Then 
        ret = idGroup 
       End If 

       'Debug.Print id2 & " " & precedentid2 & " " & idGroup 

       rs.Edit 
        rs.Fields("idGroup") = idGroup 
       rs.Update 
      End If 
      rs.MoveNext 
     Wend 
     rs.Close 
     Set rs = Nothing 
     precedentUid = ret 
    End If 
End Function 

답변

2

제안 :

  1. 당신은 (precedentUid 각 호출에 대해) 레코드의 큰 숫자를 열고있다. 대신, idGroup + id1으로 정렬 된 단일 레코드 세트를 사용하고 해당 값을 위 또는 아래로 찾으십시오.
  2. 항상 idGroup + id1으로 검색 중이므로 기본 키가되어야한다고 제안합니다. 빠른 검색을 위해 Seek 방법을 사용할 수 있습니다.
  3. 일단 기본 키가 있으면 단일 레코드 세트를 편집 할 필요가 없으며로드가 빨라집니다. idGroup을 업데이트해야하는 경우 CurrentDb.Execute과 함께 SQL 문을 사용하십시오.
  4. 캐시 (도구에 참조 마이크로 소프트 런타임 스크립팅 ->참조)를 DictionaryidGroup 검색 결과. 그렇게하면 재귀하는 동안 검색을 반복하지 않습니다.
  5. 샘플 데이터는 모두 숫자로 표시되지만 레코드 세트에서 문자열로 검색합니다. 기본 데이터 형식은 Long이어야하며 Text이 아닙니다. 이 문제에 대해 제어 할 수없는 경우 적절한 데이터 형식을 사용하여 임시 테이블을 만드는 것이 좋습니다.