使用 CSV 文件自动更新访问 Table
Updating an Access Table with a CSV File Automatically
问题背景:
我有一个 Powershell 脚本,我可以从我的 Microsoft Access 表单执行该脚本,该脚本扫描包含不同设施信息的文件夹,并生成类似于以下内容的 CSV:
SiteCode FacilityNumber DocumentType HyperlinkPath
DKFZ 10 DD1400 C:\FACILITIES DATABASE\path
DKFZ 10 FLRPLN C:\FACILITIES DATABASE\path
SMQL 17 P1 C:\FACILITIES DATABASE\path
SMQL 17 P2 C:\FACILITIES DATABASE\path
这样,每次将新文件添加到这些文件夹时,我都可以 运行 这个脚本并生成我拥有的所有内容的更新列表:
C:\...\Output\scanResults.csv
我现在需要的是获取该 CSV 文件并更新(甚至覆盖)我在 Access 数据库中拥有的 Table,它与其他 table 有关系并被使用通过数据库中的各种查询和表单。 CSV 列的命名和格式设置与 Access Table.
相同
我查看并尝试复制以下线程:
VBA procedure to import csv file into access
Access Data Project Importing CSV File In VBA
VBA Import CSV file
我找到的最接近的答案是:
Sub Import()
Dim conn as new ADODB.Connection
Dim rs as new ADODB.Recordset
Dim f as ADODB.field
conn.Open "DRIVER={Microsoft Text Driver (*.txt; *.csv)};DBQ=c:\temp;"
rs.Open "SELECT * FROM [test.txt]", conn, adOpenStatic, adLockReadOnly, adCmdText
While Not rs.EOF
For Each f In rs.Fields
Debug.Print f.name & "=" & f.Value
Next
Wend
End Sub
但这显然不会将数据写入table,我无法理解作者将Select更改为Insert的意思。
我还发现:
DoCmd.TransferText acImportDelim, "YourCustomSpecificationName", _
"tblImport", "C:\SomeFolder\DataFile.csv", False
因为这两个都是 2010 年的,我想知道在 Access 2013 中是否有更好的方法来完成这个。虽然我可以手动完成这一切,但我想将它合并到 VBA 我用来告诉 Powershell 生成 CSV 的代码,这样我就可以生成 CSV,然后立即上传。
非常感谢任何帮助或建议。总的来说,我对 Access、VBA 和 SQL 语句还是很陌生,所以这是一个非常 "learning as I go" 的过程。
我更喜欢使用 SQL 子句和查询来导入此类数据。详细信息取决于您的确切配置,但它往往看起来像这样:
SELECT *
INTO MyTable
FROM [Text;FMT=CSVDelimited;HDR=No;DATABASE=C:\...\Output].[scanResults#csv]
或将信息附加到 table:
INSERT INTO MyTable
(SiteCode, FacilityNumber, DocumentType, HyperlinkPath)
SELECT *
FROM [Text;FMT=CSVDelimited;HDR=No;DATABASE=C:\...\Output].[scanResults#csv]
这允许您在导入前进行检查(使用 WHERE
子句),仅导入特定值,并允许您在不使用外部文件的情况下进行大量自定义。
DATABASE=
后跟您的文件夹名称(如果其中有需要转义的字符,请使用 {}
),然后是您的文件名,其中 .
替换为 #
.
您可以通过将其保存为查询或将其用作 VBA 或宏中的字符串来执行它。请注意,我很少推荐宏,但您可以使用计划任务执行它们并在导入后关闭 Access。
要备份和恢复更新前后的关系,您可以使用以下功能:
Public Function DeleteRelationsGiveBackup(strTablename As String) As Collection
Dim ReturnCollection As Collection
Set ReturnCollection = New Collection
Dim i As Integer
Dim o As Integer
Do While i <= (CurrentDb.Relations.Count - 1)
Select Case strTablename
Case Is = CurrentDb.Relations(i).Table
ReturnCollection.Add DuplicateRelation(CurrentDb.Relations(i))
o = o + 1
CurrentDb.Relations.Delete CurrentDb.Relations(i).NAME
Case Is = CurrentDb.Relations(i).ForeignTable
ReturnCollection.Add DuplicateRelation(CurrentDb.Relations(i))
o = o + 1
CurrentDb.Relations.Delete CurrentDb.Relations(i).NAME
Case Else
i = i + 1
End Select
Loop
Set DeleteRelationsGiveBackup = ReturnCollection
End Function
Public Sub RestoreRelationBackup(collRelationBackup As Collection)
Dim relBackup As Variant
If collRelationBackup.Count = 0 Then Exit Sub
For Each relBackup In collRelationBackup
CurrentDb.Relations.Append relBackup
Next relBackup
End Sub
Public Function DuplicateRelation(SourceRelation As Relation) As Relation
Set DuplicateRelation = CurrentDb.CreateRelation(SourceRelation.NAME, SourceRelation.Table, SourceRelation.ForeignTable)
DuplicateRelation.Attributes = SourceRelation.Attributes
Dim i As Integer
Dim fldLoop As Field
Do While i < SourceRelation.Fields.Count
Set fldLoop = DuplicateRelation.CreateField(SourceRelation.Fields(i).NAME)
fldLoop.ForeignName = SourceRelation.Fields(i).ForeignName
DuplicateRelation.Fields.Append fldLoop
i = i + 1
Loop
End Function
然后,在导入时:
Dim colRelBackup As Collection
Set colRelBackup = DeleteRelationsGiveBackup("MyTable")
'Delete MyTable
'Import new version
RestoreRelationBackup colRelBackup
(请注意,代码很长,是几年前为一个项目开发的,并没有经过广泛测试。如果字段 name/type 不 完全 就像在导入前,备份还原可能会失败,关系将永久丢失。
一些高级架构师建议:替换数据与替换 table
替换数据更容易 - 新传入数据的结构必须与现有 table 完全相同(即相同的字段名称且没有新字段)。
- 只需对现有的 table 执行删除查询即可清除所有记录
- 然后向链接的 CSV 文件发送追加查询,将所有这些记录写入现有 table
真的很简单。
如果需要,您可以替换 tables - 而且您已经沿着这条路走下去了。您可以完全删除这些 table 关系。 table 关系功能很有用 - 但不是强制性的。作为替代,您可以在查询级别创建关系。本质上 table 关系只是自动创建查询级别的关系。如果您删除 table 关系,则必须简单地在查询级别手动创建 table 关系——它们不会自动出现。但是请注意,如果依赖级联删除或参照完整性,则删除 table 关系将撤消这些 - 因此您应该检查这些要点。
删除Table 关系不会破坏任何现有查询。他们的 table 关系连接线将保持不变。
问题背景:
我有一个 Powershell 脚本,我可以从我的 Microsoft Access 表单执行该脚本,该脚本扫描包含不同设施信息的文件夹,并生成类似于以下内容的 CSV:
SiteCode FacilityNumber DocumentType HyperlinkPath
DKFZ 10 DD1400 C:\FACILITIES DATABASE\path
DKFZ 10 FLRPLN C:\FACILITIES DATABASE\path
SMQL 17 P1 C:\FACILITIES DATABASE\path
SMQL 17 P2 C:\FACILITIES DATABASE\path
这样,每次将新文件添加到这些文件夹时,我都可以 运行 这个脚本并生成我拥有的所有内容的更新列表:
C:\...\Output\scanResults.csv
我现在需要的是获取该 CSV 文件并更新(甚至覆盖)我在 Access 数据库中拥有的 Table,它与其他 table 有关系并被使用通过数据库中的各种查询和表单。 CSV 列的命名和格式设置与 Access Table.
相同我查看并尝试复制以下线程:
VBA procedure to import csv file into access
Access Data Project Importing CSV File In VBA
VBA Import CSV file
我找到的最接近的答案是:
Sub Import()
Dim conn as new ADODB.Connection
Dim rs as new ADODB.Recordset
Dim f as ADODB.field
conn.Open "DRIVER={Microsoft Text Driver (*.txt; *.csv)};DBQ=c:\temp;"
rs.Open "SELECT * FROM [test.txt]", conn, adOpenStatic, adLockReadOnly, adCmdText
While Not rs.EOF
For Each f In rs.Fields
Debug.Print f.name & "=" & f.Value
Next
Wend
End Sub
但这显然不会将数据写入table,我无法理解作者将Select更改为Insert的意思。
我还发现:
DoCmd.TransferText acImportDelim, "YourCustomSpecificationName", _
"tblImport", "C:\SomeFolder\DataFile.csv", False
因为这两个都是 2010 年的,我想知道在 Access 2013 中是否有更好的方法来完成这个。虽然我可以手动完成这一切,但我想将它合并到 VBA 我用来告诉 Powershell 生成 CSV 的代码,这样我就可以生成 CSV,然后立即上传。
非常感谢任何帮助或建议。总的来说,我对 Access、VBA 和 SQL 语句还是很陌生,所以这是一个非常 "learning as I go" 的过程。
我更喜欢使用 SQL 子句和查询来导入此类数据。详细信息取决于您的确切配置,但它往往看起来像这样:
SELECT *
INTO MyTable
FROM [Text;FMT=CSVDelimited;HDR=No;DATABASE=C:\...\Output].[scanResults#csv]
或将信息附加到 table:
INSERT INTO MyTable
(SiteCode, FacilityNumber, DocumentType, HyperlinkPath)
SELECT *
FROM [Text;FMT=CSVDelimited;HDR=No;DATABASE=C:\...\Output].[scanResults#csv]
这允许您在导入前进行检查(使用 WHERE
子句),仅导入特定值,并允许您在不使用外部文件的情况下进行大量自定义。
DATABASE=
后跟您的文件夹名称(如果其中有需要转义的字符,请使用 {}
),然后是您的文件名,其中 .
替换为 #
.
您可以通过将其保存为查询或将其用作 VBA 或宏中的字符串来执行它。请注意,我很少推荐宏,但您可以使用计划任务执行它们并在导入后关闭 Access。
要备份和恢复更新前后的关系,您可以使用以下功能:
Public Function DeleteRelationsGiveBackup(strTablename As String) As Collection
Dim ReturnCollection As Collection
Set ReturnCollection = New Collection
Dim i As Integer
Dim o As Integer
Do While i <= (CurrentDb.Relations.Count - 1)
Select Case strTablename
Case Is = CurrentDb.Relations(i).Table
ReturnCollection.Add DuplicateRelation(CurrentDb.Relations(i))
o = o + 1
CurrentDb.Relations.Delete CurrentDb.Relations(i).NAME
Case Is = CurrentDb.Relations(i).ForeignTable
ReturnCollection.Add DuplicateRelation(CurrentDb.Relations(i))
o = o + 1
CurrentDb.Relations.Delete CurrentDb.Relations(i).NAME
Case Else
i = i + 1
End Select
Loop
Set DeleteRelationsGiveBackup = ReturnCollection
End Function
Public Sub RestoreRelationBackup(collRelationBackup As Collection)
Dim relBackup As Variant
If collRelationBackup.Count = 0 Then Exit Sub
For Each relBackup In collRelationBackup
CurrentDb.Relations.Append relBackup
Next relBackup
End Sub
Public Function DuplicateRelation(SourceRelation As Relation) As Relation
Set DuplicateRelation = CurrentDb.CreateRelation(SourceRelation.NAME, SourceRelation.Table, SourceRelation.ForeignTable)
DuplicateRelation.Attributes = SourceRelation.Attributes
Dim i As Integer
Dim fldLoop As Field
Do While i < SourceRelation.Fields.Count
Set fldLoop = DuplicateRelation.CreateField(SourceRelation.Fields(i).NAME)
fldLoop.ForeignName = SourceRelation.Fields(i).ForeignName
DuplicateRelation.Fields.Append fldLoop
i = i + 1
Loop
End Function
然后,在导入时:
Dim colRelBackup As Collection
Set colRelBackup = DeleteRelationsGiveBackup("MyTable")
'Delete MyTable
'Import new version
RestoreRelationBackup colRelBackup
(请注意,代码很长,是几年前为一个项目开发的,并没有经过广泛测试。如果字段 name/type 不 完全 就像在导入前,备份还原可能会失败,关系将永久丢失。
一些高级架构师建议:替换数据与替换 table
替换数据更容易 - 新传入数据的结构必须与现有 table 完全相同(即相同的字段名称且没有新字段)。
- 只需对现有的 table 执行删除查询即可清除所有记录
- 然后向链接的 CSV 文件发送追加查询,将所有这些记录写入现有 table
真的很简单。
如果需要,您可以替换 tables - 而且您已经沿着这条路走下去了。您可以完全删除这些 table 关系。 table 关系功能很有用 - 但不是强制性的。作为替代,您可以在查询级别创建关系。本质上 table 关系只是自动创建查询级别的关系。如果您删除 table 关系,则必须简单地在查询级别手动创建 table 关系——它们不会自动出现。但是请注意,如果依赖级联删除或参照完整性,则删除 table 关系将撤消这些 - 因此您应该检查这些要点。
删除Table 关系不会破坏任何现有查询。他们的 table 关系连接线将保持不变。