Access 2007将查询/ vba改进为按链接列表分组

时间:2012-10-04 13:22:08

标签: sql vba ms-access office-2007

我收到一些表格,其中有按链表分组的元素,我很难处理它。

该函数可以找到它,但我经常被问到自从任务调度程序启动以来它的宏在哪里或有一些内存问题。

我使用下面的代码找出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

1 个答案:

答案 0 :(得分:2)

一些建议:

  1. 您正在打开大量记录集(每次调用precedentUid)。相反,请考虑使用按idGroup + id1排序的单个记录集,并向上或向下搜索相应的值。
  2. 由于您始终在idGroup + id1上进行搜索,因此我建议将其作为主键。然后,您就可以使用Seek方法加快搜索速度。
  3. 拥有主键后,单个记录集无需可编辑,而且加载速度更快。如果必须更新idGroup,请将SQL语句与CurrentDb.Execute一起使用。
  4. idGroup中缓存搜索Dictionary的结果(参考 Microsoft脚本运行时工具 - > 参考)。这样,你就不会在递归时重复搜索。
  5. 您的示例数据似乎是所有数字,但您正在从记录集中将它们作为字符串进行检索。基础数据类型应为Long,而不是Text。如果您无法控制此情况,我会考虑使用适当的数据类型创建一个临时表。