【问题标题】:Import .csv file to MSAccess table without losing leading zeros将 .csv 文件导入 MS Access 表而不丢失前导零
【发布时间】:2017-01-08 09:44:21
【问题描述】:

我的目标是自动将 .csv 文件导入 Access 表,保留 csv 文件中的所有数据,特别是前导零。

csv 文件每次都会有不同数量的列,因此必须动态创建需要导入的表。 此外,还决定将每一列定义为 text(255)。

这是该过程的相关代码,省略了用户导航到文件夹并选择 .csv 文件的部分。

变量说明:

FilePathAndName 包含 .csv 文件的完整路径和文件名

TableName 包含我正在创建的 MSAccess 表的名称

HeaderRow 包含具有列名的 csv 文件的第一行。列名永远不会包含逗号。

ColumnNames() 是一个数组,用于保存列名本身。

SQLStatement 将保存 SQL DDL 语句来创建表

Open FilePathAndName For Input As #1

' read first row to get column names because that will change every time
Line Input #1, HeaderRow
Close #1
ColumnNames = Split(HeaderRow, ",")

' create MSAccess table via DDL commands
TableName = "GROUPS_TEST"
SQLStatement = "CREATE TABLE " & TableName & "("
For i = 0 To UBound(ColumnNames)
    SQLStatement = SQLStatement & "[" & ColumnNames(i) & "] text(255)"
    If i < UBound(ColumnNames) Then
        SQLStatement = SQLStatement & ", "
    End If
Next i
SQLStatement = SQLStatement & ")"
DoCmd.RunSQL SQLStatement

' load .csv file into the table that was just created
DoCmd.TransferText acImportDelim, , TableName, FilePathAndName, True

它可以完美地工作,包括创建表的 DoCmd.RunSQL 语句。 所有列都定义为 text(255),因为有些列必须保留前导零。 它们不是数字;它们是字母数字值。 然后麻烦就开始了。我执行 TransferText 操作并将数据从 .csv 文件导入到表中。 除了它从具有它们的值中去除前导零 即使我专门将所有列定义为 TEXT 列。

我已经用谷歌搜索了几个小时,但没有任何结果。 由于 .csv 文件的动态特性,我没有导入/导出规范。 而且我不知道这会有什么不同。

提到的一件事是在 MSAccess 中编辑文本文件的注册表设置,但我找不到细节。 我正在使用 Access 2007。 提出的另一个想法是使用 schema.ini 文件,但由于 csv 文件的动态特性,我不知道这是否可行。

我们将不胜感激地接受任何帮助。 提前致谢。

【问题讨论】:

  • 前导零是动态的还是字段长度是固定的?如果已修复,您可以设置列格式属性以保留前导零
  • 既然您正在读取文件以获取列数,那么是什么阻止您遍历该行并插入所有行?我知道这不是你想要的答案,只是说。顺便提一句。如果您真的想解决此问题,请在您的 .csv 文件顶部添加一个空/测试行,其中所有 comumns 都有文本值。它将强制访问以文本形式读取所有列,否则 Access 会在传输时转换列,而您的列是它的副作用之一。
  • @random_answer_guy - 前导零是动态的。
  • @krishKM - 是的,我希望避免遍历文件;相反,我想将其“批量插入”到表中。而且,我尝试在标题行之后插入一个测试行,其中包含有问题的列的非数字值。没有运气。它仍然剥离了后续行的前导零。感谢您的意见!
  • 这个问题很熟悉,但不知道我是怎么做到的。我认为访问评估第一行或前 10 行来识别数据类型。 (我知道它很愚蠢)如果你真的想确定,只需逐行插入,至少你知道你做了什么..

标签: csv ms-access import vba leading-zero


【解决方案1】:

不要使用导入文件中的字段名称,而是将导入表中的所有字段命名为 F1、F2、F3 等。 将 HasFieldNames 参数设置为 false。那么第一行将永远是文本。您可以稍后删除该行。 然后将字段名称更改为您想要的名称或将数据插入另一个表。无论如何,我总是使用这种方法,以便在将导入数据插入最终目标表之前对其进行清理。

【讨论】:

  • 将 HasFieldNames 设置为 false。出现错误“INSERT INTO 语句包含以下未知字段名称:'F1'。等等,等等。
  • 而且,字段名称必须是第一行,因为这是我确定创建表的列名称的方式。
【解决方案2】:

这是对我有用的解决方案;感谢 Ryan Griffin 对 Stack Overflow 上类似问题的回答。

重申要求:

1) 将 .csv 文件导入 MSAccess

2) 必须在包含它们的字段中保留所有前导零

3) .csv 文件是动态的;每次导入时,列数可以(并且通常会)变化

4) 数据类型可以是所有列的文本

5) 给定列的数据长度永远不会 > 255

6) .csv 文件的第一行将始终包含列名,并且列名中永远不会有逗号

7) 列可能有也可能没有引号分隔符;如果任何列包含逗号,则该列将用引号分隔;否则可能会也可能不会。

这是一个示例 .csv 文件:

姓名、部门、​​分机

“ManyJohns,约翰”,02,0987

John Smallberries,"收购","32939"

“John Bigbootie”,0001,GIGO


系统设置:Windows 7 和 MSAccess 2007

我知道几年前有一个注册表设置对类似项目有所帮助。 Win7路径为HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Text

ImportMixedTypes 的值从 Majority Type 更改为 Text

第一次尝试:使用 TransferText 操作

变量:TableName 和 FilePathAndName

DoCmd.TransferText acImportDelim, , TableName, FilePathAndName, True

请注意,没有导入规范,因为如上所述,它每次都可以更改。 结果:删除了前导零并删除了文本值


第二次尝试:将 .csv 文件作为 Access 对象打开

变量:TableName、FilePath 和 FileName

SQLStatement = "INSERT INTO " & TableName & " SELECT * FROM [TEXT;FMT=Delimited;HDR=YES;IMEX=1;CharacterSet=437;DATABASE=" & FilePath & "].[" & FileName & "]"
DoCmd.RunSQL SQLStatement

结果:我以前从未见过这种用法;有点酷,我想。但是,它也删除了前导零并删除了文本值。


第三次尝试:动态创建导入/导出规范 这是 Ryan Griffin 的帖子,我根据我的目的调整了他的解决方案。谢谢你,先生;我向你致敬。

Access Data Project Importing CSV File In VBA

而且,成功了。

由于我的 .csv 文件的动态特性,这里是基于 Ryan 工作的最终代码。 我在这里没有包含变量声明;如果有兴趣,请告诉我,我会整理一些更精美的东西。

Private Function CreateImportSpecification()

    'based on solution from Ryan Griffin 21-JUN-2012
    ImportSpecificationName = "ImportSpec_" & TableName

    xml = ""
    xml = xml & "<?xml version=""1.0"" encoding=""utf-8"" ?>" & vbCrLf
    xml = xml & "<ImportExportSpecification Path=" & Chr(34) & FilePathAndName & Chr(34) & " xmlns=""urn:www.microsoft.com/office/access/imexspec"">" & vbCrLf
    xml = xml & "   <ImportText TextFormat=""Delimited"" FirstRowHasNames=""true"" FieldDelimiter="","" CodePage=""437"" Destination=" & Chr(34) & TableName & Chr(34) & " >" & vbCrLf
    xml = xml & "      <DateFormat DateOrder=""MDY"" DateDelimiter=""/"" TimeDelimiter="":"" FourYearDates=""true"" DatesLeadingZeros=""false"" />" & vbCrLf
    xml = xml & "      <NumberFormat DecimalSymbol=""."" />" & vbCrLf
    xml = xml & "         <Columns PrimaryKey=""{none}"">" & vbCrLf

    ' dynamically populate the 'FieldName' property of the <Column> attribute
    For i = 0 To UBound(ColumnNames)
        xml = xml & "            <Column Name=""Col" & (i + 1) & """ FieldName=""" & ColumnNames(i) & """ Indexed=""NO"" SkipColumn=""false"" DataType=""Text"" Width=""255"" />" & vbCrLf
    Next i

    xml = xml & "         </Columns>" & vbCrLf
    xml = xml & "   </ImportText>" & vbCrLf
    xml = xml & "</ImportExportSpecification>"

    ' if a specification already exists for this table, delete it
    With CurrentProject.ImportExportSpecifications
        For i = 0 To .Count - 1
            If .Item(i).Name = ImportSpecificationName Then
                .Item(i).Delete
                Exit For
            End If
        Next i
        ' add the specification to the database
        .Add ImportSpecificationName, xml
        ' could execute ImportSpecificationName right here
        ' but would need to loop through the ImportExportSpecifications again
        ' to make sure you had the right one
    End With

    DoCmd.RunSavedImportExport ImportSpecificationName

End Function

我唯一能想到的是,MSAccess 在导入 .csv 文件时会忽略注册表项(或者我修改了错误的项)。 最终,唯一对我有用的是动态创建导入/导出规范。 欢迎任何其他意见。

【讨论】:

    猜你喜欢
    • 2022-11-17
    • 1970-01-01
    • 2011-03-11
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    相关资源
    最近更新 更多