sql - 访问,使用 VBA 自动匹配 2 个记录集之间的记录
问题描述
我在 Access 中有一个数据库,在 excel 中有另一个表。
我正在尝试在 access 中构建一个协调宏,这将有望标记 Access 中在 excel 中具有匹配条目的所有记录。excel也会被标记掉,所以我会知道哪些记录没有匹配到手动查看。
到目前为止,我所做的是将 excel 表转换为数组,然后将其移动到记录集“ldict”中以减少工作表交互,并有望加快宏的速度。
我对 Access 中的表做了同样的事情,并将其移动到记录集“RS”中。
在这一点上,我一直在使用嵌套循环。它将遍历 ldict 中的每条记录,然后遍历 RS 中的每条记录以查找匹配项。
当它找到匹配项时,我在 RS 中有一个布尔字段“CMN_REV”,它将设置为 TRUE 以指示它已匹配。
在 ldict 中,它将从 RS 复制匹配的 PK_ID,作为匹配内容的记录。
Dim xl As Excel.Application, wb As Excel.Workbook, lfilepath As String, ldict As ADODB.Recordset, lrow As Long, i As Long, _
legacy As Excel.Worksheet, legacy2 As Excel.Worksheet, str As String, arr() As Variant
'setup ldict
Set ldict = New ADODB.Recordset
With ldict.Fields
.Append ......
End With
ldict.Open
'set legacy file
lfilepath = Dir(Application.CurrentProject.Path & "\test.csv")
Set xl = CreateObject("Excel.application")
With xl
.DisplayAlerts = False
.Visible = True
Set wb = .Workbooks.Open(Application.CurrentProject.Path & "\" & lfilepath)
Set legacy = wb.Worksheets(1)
'move excel to array to recordset.
With legacy
lrow = .Range("A" & .Rows.count).End(xlUp).Row
arr = .Range("A1:AM" & lrow)
For i = 2 To UBound(arr, 1)
With ldict
.AddNew
.......
.Update
End With
Next i
Erase arr()
Set legacy2 = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.count))
legacy2.Name = "Results"
wb.SaveAs FileName:=Application.CurrentProject.Path & "\" & "Output", FileFormat:=xlOpenXMLWorkbook, _
ConflictResolution:=Excel.XlSaveConflictResolution.xlLocalSessionChanges
End With
.DisplayAlerts = True
End With
'setup RS
Dim rs As Recordset, qdf As DAO.QueryDef
Set rs = CurrentDb.OpenRecordset("Unpaid query")
Set qdf = CurrentDb.CreateQueryDef("")
qdf.sql = "Update AR_Consolidated set CMN_REV = '0'"
qdf.Execute dbFailOnError
ldict.MoveFirst
rs.MoveFirst
'compare loop
While Not ldict.EOF
'end of rs wend sets absolute to -1. check to reset to first position
If rs.EOF = True Then
rs.MoveFirst
End If
While Not rs.EOF
'convert rs expiry to dates
Select Case Left(rs("MON_YR"), 3)
Case Is = "JAN"
i = 1
Case Is = "FEB"
i = 2
Case Is = "MAR"
i = 3
Case Is = "APR"
i = 4
Case Is = "MAY"
i = 5
Case Is = "JUN"
i = 6
Case Is = "JUL"
i = 7
Case Is = "AUG"
i = 8
Case Is = "SEP"
i = 9
Case Is = "OCT"
i = 10
Case Is = "NOV"
i = 11
Case Is = "DEC"
i = 12
End Select
'check conditions
If rs("CMN_REV") = False _
And (Trim(ldict("area")) = Trim(rs("area")) Or Trim(ldict("area")) = Trim(rs("MIC"))) _
And Trim(ldict("Firm")) = Trim(rs("Firm")) _
And ldict("Product") = rs("Product_Code") _
And ldict("Expiry") = DateSerial(Right(rs("MON_YR"), 2), i, "01") _
And Round(ldict("Price"), 3) = Round(Val(rs("Price")), 3) _
And ldict("Date") = rs("Date") _
And ldict("Quantity") = rs("Quantity") And ldict("Amount") = rs("Amount") _
And ldict("BuySell") = rs("BUY/SELL") _
And ldict("Currency") = rs("CurrCode") _
And ldict("Amount") = rs("Amount") _
Then
'perform actions if matched
'set matched indicator in rs
rs.Edit
rs![CMN_REV] = True
rs.Update
ldict("PK_ID").Value = rs("PK_ID").Value
ldict.Update
GoTo a
End If
rs.MoveNext
Wend
a:
ldict.MoveNext
Wend
'copy from ldict into excel
If ldict.BOF = False And ldict.EOF = False Then
ldict.MoveFirst
End If
legacy2.Range("A2").CopyFromRecordset ldict
wb.Save
虽然代码运行良好,但不幸的是太慢了。每个记录集我平均有 100k 条记录,如果不是几天,它似乎需要几个小时。
当它移动到 ldict 中的每条记录时,它将再次循环通过 RS 的开头。
我已经考虑在 RS 中找到匹配的记录时可能会删除它,因此它不必在下一个循环中再次查看相同的记录,但我相信这也会将它从我的 Access 表中删除。
我已经阅读了一些建议,即使用连接的 SQL 查询会更快,但我不确定如何实现相同的结果。
有人有更好的建议吗?
谢谢你。
解决方案
使用 SQL 而不是 VBA 执行此操作的一种可能性是从 Excel 工作簿在 Access 中创建链接表。然后,您可以对这两个数据集运行查询。
我不确定是否直接更新您的 Excel 文件,但您至少应该能够使用选择查询来查看 Excel 中的哪些行不匹配。未经测试,但总体思路是这样的:
select *
from [YourExcelTable] e
where not exists (
select 1
from [YourAccessTable] a
where (Trim(e.area) = Trim(a.area) Or Trim(e.area) = Trim(a.MIC))
And Trim(e.Firm) = Trim(a.Firm)
And e.Product = a.Product_Code
And e.Expiry = DateSerial(Right(a.MON_YR, 2), i, "01")
And Round(e.Price, 3) = Round(Val(a.Price), 3)
And e.Date = a.Date
And e.Quantity = a.Quantity
And e.Amount = a.Amount
And e.BuySell = a.[BUY/SELL]
And e.Currency = a.CurrCode
And e.Amount = a.Amount
)
编辑:根据下面的问题,如果您想找到匹配项,并且希望能够显示两个表中的字段,则可以使用 JOIN 而不是 EXISTS。您可能可以减少连接中的字段数量,但由于我不熟悉您的数据,我将在这里假设所有字段都是进行正确匹配所必需的。
select e.*, a.ID
from [YourExcelTable] e
inner join [YourAccessTable] a
On (Trim(e.area) = Trim(a.area) Or Trim(e.area) = Trim(a.MIC))
And Trim(e.Firm) = Trim(a.Firm)
And e.Product = a.Product_Code
And e.Expiry = DateSerial(Right(a.MON_YR, 2), i, "01")
And Round(e.Price, 3) = Round(Val(a.Price), 3)
And e.Date = a.Date
And e.Quantity = a.Quantity
And e.Amount = a.Amount
And e.BuySell = a.[BUY/SELL]
And e.Currency = a.CurrCode
And e.Amount = a.Amount
推荐阅读
- c# - 从 ListViewItem 上的按钮获取索引
- drupal - Drupal 8将变量从父段落传递到树枝文件中的子段落
- javascript - 如何在 JSDoc typedefs 中干燥相似的属性
- json - AWS Lambda,测试按钮做什么类型的请求?
- python - 在 Python 中对数组进行滚动求和
- sql-server - 如何透视具有多个列值的 SQL Server 表?
- javascript - 您如何注释返回状态切片的函数的流类型?
- nfc - 提示文件从 NFC 标签下载到手机
- android - 如何从保存在 firebase 数据库中的分数继续游戏?安卓应用
- python - 对于大小为 100 的轴 0,索引超出范围