我在Access中的AutoExec宏上运行以下函数。
问题是运行它需要大约40秒(!!!),这对于大约200条记录来说太长了。
有人可以建议任何方法来最小化这个运行时间吗?
此代码的目标基本上是检查RefreshedDatas table中的每条记录,如果多个值'PartNo字段中的一个值存在于来自其他table的2个可能字段中(请参阅图片:我必须检查SparPartNo字段是否包含SerialPartNo字段的值)。如果是,我会在WPRC Part字段中写YES,否则为NO。
举个例子,
我检查并发现代码的第5部分是39秒,而前4部分需要1秒。
Function PopulationOfWPRCField()
'1) Create an access to the PartNo field (=Recordset) and store all its values in an array called arrayPartNo
Dim conn As New ADODB.Connection
Dim connStr As String
Dim rs As ADODB.Recordset
Dim PartNoSQL As String
Dim arrayPartNo() As Variant
connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & "PathtoMyAccessDatabase\" & "NewVersion.accdb" & ";"
conn.ConnectionString = connStr
conn.Open
Set rs = New ADODB.Recordset
PartNoSQL = "SELECT PartNo FROM RefreshedDatas" '"SELECT PartNo FROM 12Dec"
rs.Open PartNoSQL, conn, adOpenStatic, adLockReadOnly, adCmdText
If Not rs.EOF Then
arrayPartNo = rs.GetRows
End If
'Set rs = Nothing
'2) Same with fields SerialPartNo and SparePartNo from the WPRC_List (+ShipmentID for the 4th part of this code)
Dim arraySerialPartNo() As Variant
Dim arraySparePartNo() As Variant
Dim arrayShipmentID() As Variant
Dim SerialPartNoSQL As String
Dim SparePartNoSQL As String
Dim ShipmentIDSQL As String
'For SpartNo
Set rs = New ADODB.Recordset
SparePartNoSQL = "SELECT SparePartNo FROM WPRC_Parts_List"
rs.Open SparePartNoSQL, conn, adOpenStatic, adLockReadOnly, adCmdText
If Not rs.EOF Then
arraySparePartNo = rs.GetRows
End If
'For i = 0 To UBound(arraySparePartNo, 2)
' Debug.Print arraySparePartNo(0, i)
'Next i
Set rs = Nothing
'For SerialNo
Set rs = New ADODB.Recordset
SerialPartNoSQL = "SELECT SerialPartNo FROM WPRC_Parts_List"
rs.Open SerialPartNoSQL, conn, adOpenStatic, adLockReadOnly, adCmdText
If Not rs.EOF Then
arraySerialPartNo = rs.GetRows
End If
'For i = 0 To UBound(arraySerialPartNo, 2)
' Debug.Print arraySerialPartNo(0, i)
'Next i
Set rs = Nothing
'For ShipmentID
Set rs = New ADODB.Recordset
ShipmentIDSQL = "SELECT [Shipment ID] FROM RefreshedDatas"
rs.Open ShipmentIDSQL, conn, adOpenStatic, adLockReadOnly, adCmdText
If Not rs.EOF Then
arrayShipmentID = rs.GetRows
End If
'For i = 0 To UBound(arrayShipmentID, 2)
' Debug.Print arrayShipmentID(0, i)
'Next i
Set rs = Nothing
Set conn = Nothing
'3) We calculate the size of the GoodArray() we'll declare later on so that we can declare it properly
Dim h As Integer
Dim longest As Integer
longest = 0
For h = 0 To UBound(arrayPartNo, 2) ' in this loop we search for the longest character in arrayPartNo and store its size in "longest"
If Len(arrayPartNo(0, h)) > longest Then longest = Len(arrayPartNo(0, h))
Next h
'MsgBox longest '63 in this case
h = (longest + 1) / 8 ' since h was only used in the loop above we reuse it to store this = 8 -> size of the 2nd dimension of GoodArray() , it represents the biggest number of PartNo a cell in arrayPartNo contains
longest = UBound(arrayPartNo, 2) ' same here, we just reuse the variable to store this -> size of the 1st dimension of GoodArray () , it represents the number of cells(=records) in arrayPartNo ( in the MainForm)
'4) Declaration of the 2-dimensional array GoodArray() and population of it
Dim NumberOfPartNo As Integer ' Number of PartNo in a specific row
Dim length As Integer ' length of a correct PartNo
Dim i As Integer
Dim GoodArray() As Variant ' this is a 2 dimensional array where 1st dimension contains UBound(arrayPartNo, 2) cells and 2nd dimension contains the number of PartNo (=NumberOfPartNo) for the row determined by the 1st dimension)
' reason for (longest+1)/8 : we have the following equation : x*7 + (x-1)= longest where x is the number of PartNo( but for the record which has the most PartNo) and (x-1) is the number of ";" separating all those PartNo, the total gives the number of character of the record (= longest for the record with the most PartNo)
ReDim Preserve GoodArray(longest, h)
For i = 0 To UBound(arrayPartNo, 2)
length = 7
NumberOfPartNo = 0
If Len(arrayPartNo(0, i)) > 0 Then
Do
GoodArray(i, NumberOfPartNo) = Mid(arrayPartNo(0, i), length + 1 - 7, 7)
NumberOfPartNo = NumberOfPartNo + 1
length = length + 8
Loop While Len(arrayPartNo(0, i)) >= length ' since we use such a loop it allows any PartNo to go through it even if it has less than 6 characters
End If
Next i
'5) Comparison of the arrays : For each element contained in GoodArray() check if it is included in arraySerialPartNo or arraySparePartNo
Dim j As Integer
Dim k As Integer
'Dim OnList As Boolean
For i = 0 To UBound(GoodArray, 1)
k = 0
'OnList = False
Do Until GoodArray(i, k) = ""
For j = 0 To UBound(arraySerialPartNo, 2)
If arraySerialPartNo(0, j) = GoodArray(i, k) Then
DoCmd.RunSQL "UPDATE RefreshedDatas Set [WPRC Part] = 'Yes' WHERE [Shipment ID] = " & arrayShipmentID(0, i)
'OnList = True
GoTo Prochain
End If
Next j
For j = 0 To UBound(arraySparePartNo, 2)
If arraySparePartNo(0, j) = GoodArray(i, k) Then
DoCmd.RunSQL "UPDATE RefreshedDatas Set [WPRC Part] = 'Yes' WHERE [Shipment ID] = " & arrayShipmentID(0, i)
'OnList = True
GoTo Prochain
End If
Next j
k = k + 1
Loop
DoCmd.RunSQL "UPDATE RefreshedDatas Set [WPRC Part] = 'No' WHERE [Shipment ID] = " & arrayShipmentID(0, i)
Prochain:
Next i
End Function
答案 0 :(得分:2)
没有真正的答复,但是......
IF 您的2张表格中有正确的主键,和
IF 您在2个表之间定义了一个正确的关系(具有参照完整性)
那么你甚至不必检查是否匹配,你可以删除该代码。
无论如何,如果我理解的话,只需更新查询即可完成代码。我没有理由使用数组。
我甚至认为你不需要更新查询。只需使用SELECT
查询LEFT JOIN
,其中包含指示“匹配”或“不匹配”的公式
答案 1 :(得分:1)
此代码的目标基本上是检查中的每条记录 RefreshedDatas表,如果多个值中的一个值为' PartNo字段存在于其他表的2个可能字段中(请参阅 图片中的结构:我要检查是否有SparPartNo字段 SerialPartNo字段包含值)。如果是的话,我会写 WPRC Part字段中为YES,否则为NO。
据我所知,你需要这个......
UPDATE RefreshedDatas
SET WPRC = "NO"; // Everything is set to no.
现在测试这个sql,它将列出所有部件以及partno集合中找到的任何部件。 PartNo.Value是访问多值字段中项目的方法。
Select
R.SparePartNo
R.SerialPartNo
iif(isnull(R2.PartNo.value),"No", "Yes") as [Part found]
FROM RefreshedDatas as R left join RefreshedDatas as R2
ON (R.SparePArtNo = R2.PartNo.Value OR R.SerialPartNo = R2.PArtNo.Value);
备份您的表并尝试此更新。与连接表类似,您也可以使用子查询从另一个表或同一个表中选择和查找值。
UPDATE RefreshedDatas
SET WPRC = "YES"
WHERE
//if SparePartNo is available in the PartNo collection
RefreshedDatas.SparePartNo in (SELECT P.PartNo.Value from RefreshedDatas as P WHERE P.ID = RefreshedDatas.ID)
// or if the SerialPartNo is available in the partNo Collection.
OR RefreshedDatas.SerialPartNo (SELECT S.PartNo.Value from RefreshedDatas as S WHERE S.ID = RefreshedDatas.ID)
没有办法测试代码,但你应该知道它在SQL中是如何工作的。 删除" P WHERE P.ID = RefreshedDatas.ID"如果您想在整个PartNo集合中搜索零件号而不是在同一行