【问题标题】:Split Field Into Multiple Records in Access DB在 Access DB 中将字段拆分为多条记录
【发布时间】:2016-11-21 04:49:32
【问题描述】:

我有一个 MS Access 数据库,它有一个名为 Field1 的字段,其中包含多个用逗号分隔的值。即,

Value1,Value 2, Value3, Value 4,Value5

我试图不将值拆分为单独的字段,而是通过复制记录并将每个值存储在另一个字段中。这将使得包含具有三个值的单元格的记录将被复制三次,每条记录的值都在新字段中包含的值中变化。例如,

查询/运行模块前:

+-----------+------------------------+ | App Code | Field1 | +-----------+------------------------+ | AB23 | Value1, Value 2,Value3 | +------------------------------------+

查询/运行模块后:

+-----------------------------------------------+ | App Code | Field1 | Field2 | +-----------+------------------------+----------+ | AB23 | Value1, Value 2,Value3 | Value1 | +-----------+------------------------|----------+ | AB23 | Value1, Value 2,Value3 | Value 2 | +-----------+------------------------+----------+ | AB23 | Value1, Value 2,Value3 | Value3 | +-----------+------------------------+----------+

到目前为止,我发现了几个关于拆分字段intotwo甚至several不同字段的问题,但是我没有找到任何垂直拆分记录的解决方案。在这些解决方案中,有些使用查询,有些使用模块,但我也不确定哪个最有效,所以我决定使用 VBA 模块。

所以,这是我发现迄今为止最有用的 VBA 模块:

Function CountCSWords (ByVal S) As Integer
      ' Counts the words in a string that are separated by commas.

      Dim WC As Integer, Pos As Integer
         If VarType(S) <> 8 Or Len(S) = 0 Then
           CountCSWords = 0
           Exit Function
         End If
         WC = 1
         Pos = InStr(S, ",")
         Do While Pos > 0
           WC = WC + 1
           Pos = InStr(Pos + 1, S, ",")
         Loop
         CountCSWords = WC
      End Function

      Function GetCSWord (ByVal S, Indx As Integer)
      ' Returns the nth word in a specific field.

      Dim WC As Integer, Count As Integer, SPos As Integer, EPos As Integer
         WC = CountCSWords(S)
         If Indx < 1 Or Indx > WC Then
           GetCSWord = Null
           Exit Function
         End If
         Count = 1
         SPos = 1
         For Count = 2 To Indx
           SPos = InStr(SPos, S, ",") + 1
         Next Count
         EPos = InStr(SPos, S, ",") - 1
         If EPos <= 0 Then EPos = Len(S)
         GetCSWord = Trim(Mid(S, SPos, EPos - SPos + 1))
      End Function

但是,我如何在 Access Query 中使用它来实现上述预期结果?否则,除了查询(即仅使用 VBA 模块)之外,是否有更好的方法得出相同的结论?

编辑

请注意,表中的主键是Application Code,而不是自动编号。此主键是文本且不同的。为了拆分记录,这将需要复制主键,这很好。

【问题讨论】:

  • 您可以在 VBA 中使用 Field1 上的 Split & Trim 使用更简单的循环来执行此操作 - 您是否专门询问仅使用查询?
  • 为了清楚起见,我将进行编辑,感谢您指出这一点。我不是在寻找一个只涉及查询的解决方案,而是一个能够有效完成工作的解决方案 - 如果这需要涉及 VBA 的建议,那么欢迎!
  • @HansUp:是的,确实如此。主键是App Code
  • @HansUp:出于好奇,为什么用这种方法解析Field1 会更快?另外,感谢您提供有趣的解决方案 - 这很实用,因为它可以与之后的查询合并。 :)
  • @HansUp - 如果您并行使用两个记录集,则在构建第一个记录集查询以仅处理未调整的记录(字段 2 中没有数据,字段 1 中的逗号)和第二个记录集时没有任何冲突是仅附加。请参阅下面的建议。

标签: sql ms-access vba ms-access-2010


【解决方案1】:

这是在 Table1 中使用 Field1、Field2 的示例代码

Option Explicit

Public Sub ReformatTable()

    Dim db          As DAO.Database
    Dim rs          As DAO.Recordset
    Dim rsADD       As DAO.Recordset

    Dim strSQL      As String
    Dim strField1   As String
    Dim strField2   As String
    Dim varData     As Variant
    Dim i           As Integer

    Set db = CurrentDb

    ' Select all eligible fields (have a comma) and unprocessed (Field2 is Null)
    strSQL = "SELECT Field1, Field2 FROM Table1 WHERE ([Field1] Like ""*,*"") AND ([Field2] Is Null)"

    Set rsADD = db.OpenRecordset("Table1", dbOpenDynaset, dbAppendOnly)

    Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
    With rs
        While Not .EOF
            strField1 = !Field1
            varData = Split(strField1, ",") ' Get all comma delimited fields

            ' Update First Record
            .Edit
            !Field2 = Trim(varData(0)) ' remove spaces before writing new fields
            .Update

            ' Add records with same first field 
            ' and new fields for remaining data at end of string
            For i = 1 To UBound(varData)
                With rsADD
                    .AddNew
                    !Field1 = strField1
                    !Field2 = Trim(varData(i)) ' remove spaces before writing new fields
                    .Update
                End With
            Next
            .MoveNext
        Wend

        .Close
        rsADD.Close

    End With

    Set rsADD = Nothing
    Set rs = Nothing
    db.Close
    Set db = Nothing

End Sub

编辑

更新示例以生成新的主键

如果您必须根据之前的 Appcode 生成一个新的 AppCode(并且假设 AppCode 是一个文本字段),您可以使用此示例根据最后一个 appcode 生成一个唯一的主键。

Option Explicit

Public Sub ReformatTable()

    Dim db          As DAO.Database
    Dim rs          As DAO.Recordset
    Dim rsADD       As DAO.Recordset

    Dim strSQL      As String
    Dim strField1   As String
    Dim strField2   As String
    Dim varData     As Variant
    Dim strAppCode  As String
    Dim i           As Integer

    Set db = CurrentDb

    ' Select all eligible fields (have a comma) and unprocessed (Field2 is Null)
    strSQL = "SELECT AppCode, Field1, Field2 FROM Table1 WHERE ([Field1] Like ""*,*"") AND ([Field2] Is Null)"

    ' This recordset is only used to Append New Records
    Set rsADD = db.OpenRecordset("Table1", dbOpenDynaset, dbAppendOnly)

    Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
    With rs
        While Not .EOF

            ' Do we need this for newly appended records?
            strAppCode = !AppCode

            strField1 = !Field1
            varData = Split(strField1, ",") ' Get all comma delimited fields

            ' Update First Field
            .Edit
            !Field2 = Trim(varData(0)) ' remove spaces before writing new fields
            .Update

            ' Add new fields for remaining data at end of string
            For i = 1 To UBound(varData)
                With rsADD

                    .AddNew

                    ' ***If you need a NEW Primary Key based on current AppCode
                    !AppCode = strAppCode & "-" & i

                    ' ***If you remove the Unique/PrimaryKey and just want the same code copied
                    !AppCode = strAppCode

                    ' Copy previous Field 1
                    !Field1 = strField1

                    ' Insert Field 2 based on extracted data from Field 1
                    !Field2 = Trim(varData(i)) ' remove spaces before writing new fields
                    .Update
                End With
            Next
            .MoveNext
        Wend

        .Close
        rsADD.Close

    End With

    Set rsADD = Nothing
    Set rs = Nothing
    db.Close
    Set db = Nothing

End Sub

【讨论】:

  • 不错。循环中的注释应为 ' Update First record' Add new records 以避免混淆。 :)
  • 谢谢!我只是将它调整到我的数据库并尝试一下。我还在我的问题的第一个表格中做了一个小的编辑,以更好地反映我的情况,但我现在正在编码。 :)
  • 什么是“小编辑”?你的主键是如何定义的?它是自动编号 - 还是基于 Field1?如果您想“更好地反映您的情况”,请务必更新您的问题。只有掌握了正确的信息,我们才能解决问题。
  • 该编辑删除了第一个表中的第二个字段,因为该字段事先不会存在于数据库中。我已更新我的问题以包含您要求的信息。
  • 我的主键没有重复项。如果运行宏导致重复行,从而导致主键重复,那么这对我来说不是问题。但是,如果主键必须始终是唯一的(我真的不知道它是否必须,因为我是 VBA 新手),那么请告诉我,我可以相应地更改主键。如果您还有什么想知道的,请告诉我,而不是制作刻薄的 cmets。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 2013-07-16
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多