【问题标题】:Using VBA & VLOOKUP to reorganize column ranges into rows使用 VBA 和 VLOOKUP 将列范围组织成行
【发布时间】:2020-06-05 01:34:13
【问题描述】:

我有两列 2019 年,一列包含月份,另一列对应于该月。我想用几个月作为标题和下面的金额重新组织它,如所附屏幕截图所示。

我为第一对使用了 VLOOKUP,但有超过 100,000 行,手动更新每个 VLOOKUP 的范围需要很长时间。

问题在于并非所有数据都是统一的。如果数据在 1 月开始并在 12 月结束,那就太好了,但事实并非如此。看第二张截图

其中显示了从 7 月开始到 12 月结束的数据,还有一些从 1 月开始到 7 月结束的数据。在数据集的末尾,有数百个新账户在 12 月开设,因此唯一可用的数据仅为 12 月份的数据。所以,它会有所不同。

有没有办法利用 VBA 和 VLOOKUP 自动对具有一个标题的列进行排序,即第 1-12 个月,以及下面的所有金额?然后,这些数据将与用户帐户信息合并,这就是为什么我希望将它们全部放在 1 行中。

如果您有其他建议,请告诉我。任何帮助表示赞赏!

附:我发现此链接对于转置由空白行分隔的范围很有用:VBA to transpose data based on empty lines

如何将 VLOOKUP 加入其中?

【问题讨论】:

    标签: excel vba vlookup


    【解决方案1】:

    这是一个选项。它使用月份来确定放置值的列(从 D 开始)。一旦在数据集之间找到一个或多个空白行,它就会移动到新行。

    Option Explicit
    
    Public Sub Process()
    
        Dim TargetRow As Long
        Dim SourceRange As Range
        Dim DateCell As Range
        Dim LastRowWasBlank As Boolean
    
        Set SourceRange = ActiveSheet.Range("A2:A" & ActiveSheet.Cells(1048576, 1).End(xlUp).Row)
        TargetRow = 2
        For Each DateCell In SourceRange
            If DateCell.Cells(1, 1) <> "" Then
                LastRowWasBlank = False
                ActiveSheet.Cells(TargetRow, 3 + Month(DateCell.Cells(1, 1))) = DateCell.Cells(1, 2)
            Else
                If LastRowWasBlank <> True Then
                    LastRowWasBlank = True
                    TargetRow = TargetRow + 1
                End If
            End If
        Next
    
    End Sub
    

    【讨论】:

      【解决方案2】:

      您似乎已经找到了使用 VLookup 获取数据的解决方案。您没有找到如何将公式复制到 100K 单元格的解决方案。在这里。

      1. 使用原始公式选择单元格
      2. 复制(可以使用Ctl+C)
      3. 在主页选项卡上单击查找和选择,然后转到...
      4. Reference 字段中写入目标范围,如 B2:K500000
      5. 单击确定(这将选择目标范围)
      6. Enter(这将完成粘贴操作)

      【讨论】:

      • 感谢您的回复。这不起作用,因为 vlookup 中使用的范围是动态的。例如,A1:B13 是用于第一行的范围。范围 A17:B28,是构成第二行的第二个范围,依此类推。
      • 结果的每一行都必须在 C:C 中有一个标识符,并且必须从某个地方获取,而不是包含在您的帖子中。请修改您的数据图片以包含该标识符。
      • 没有。感谢您的帮助!
      【解决方案3】:

      用空单元格转置

      • 将完整代码复制到标准模块中(例如Module1)。
      • 仔细调整常量部分中的值。
      • 只运行SubFunctionSub 调用。

      守则

      Sub transposeMonths()
      
          ' Define constants.
          Const srcNameOrIndex As Variant = "Sheet1"
          Const FirstRow As Long = 2
          Const SourceColumn As Long = 1
          Const ValueColumn As Long = 2
          Const tgtNameOrIndex As Variant = "Sheet1"
          Const tgtFirstCell As String = "D1"
          Const Separator As String = "-"
          Dim CurrYear As Long: CurrYear = 2019
          Dim Months As Variant
          Months = Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", _
                         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
          Dim wb As Workbook: Set wb = ThisWorkbook
      
          ' Add Separator and Current Year to Months Array.
          Dim ubM As Long: ubM = UBound(Months)
          Dim j As Long
          For j = 0 To ubM
              Months(j) = Months(j) & Separator & CurrYear
          Next j
          Months = Application.Transpose(Application.Transpose(Months))
          ubM = ubM + 1
      
          ' Read from Source Ranges to Source Arrays.
          Dim src As Worksheet: Set src = wb.Worksheets(srcNameOrIndex)
          Dim Source(1) As Variant
          Source(0) = getColumnValues(src, SourceColumn, FirstRow)
          Dim ubS As Long: ubS = UBound(Source(0))
          Source(1) = src.Cells(FirstRow, ValueColumn).Resize(ubS)
          Set src = Nothing
      
          ' Count unique items.
          Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
          Dim CurrMonth As String, i As Long
          For i = 1 To ubS
              CurrMonth = Source(0)(i, 1)
              If CurrMonth <> "" Then
                  dict(CurrMonth) = dict(CurrMonth) + 1
              End If
          Next i
      
          ' Write from Source Arrays to Target Array.
          Dim Target As Variant
          ReDim Target(1 To Application.Max(dict.Items) + 1, 1 To ubM)
          For j = 1 To ubM
              Target(1, j) = Months(j)
          Next j
          For i = ubS To 1 Step -1
              CurrMonth = Source(0)(i, 1)
              If CurrMonth <> "" Then
                  Target(dict(CurrMonth) + 1, Application.Match(CurrMonth, Months, 0)) _
                    = Source(1)(i, 1)
                  dict(CurrMonth) = dict(CurrMonth) - 1
              End If
          Next i
      
          ' Write from Target Array to Target Range.
          Dim tgt As Worksheet: Set tgt = wb.Worksheets(tgtNameOrIndex)
          tgt.Range(tgtFirstCell).Resize(UBound(Target), UBound(Target, 2)) = Target
      
          ' Inform user.
          MsgBox "Data copied.", vbInformation, "Success"
      
      End Sub
      
      ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
      ' Purpose:      Writes the values of a non-empty one-column range starting     '
      '               from a specified row, to a 2D one-based one-column array.      '
      ' Returns:      A 2D one-based one-column array.                               '
      ' Remarks:      If the column is empty or its last non-empty row is above      '
      '               the specified row or if an error occurs the function will      '
      '               return an empty variant. Therefore the function's result       '
      '               can be tested with "IsEmpty".                                  '
      ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
      Function getColumnValues(Sheet As Worksheet, _
                               Optional ByVal AnyColumn As Variant = 1, _
                               Optional ByVal FirstRow As Long = 1) _
              As Variant
      
          On Error GoTo exitProcedure
          Dim rng As Range
          Set rng = Sheet.Columns(AnyColumn).Find("*", , xlValues, , , xlPrevious)
          If rng Is Nothing Then Exit Function
          If rng.Row < FirstRow Then Exit Function
          Set rng = Sheet.Range(Sheet.Cells(FirstRow, AnyColumn), rng)
      
          Dim Result As Variant
          If rng.Rows.Count = 1 Then
              ReDim Result(1 To 1, 1 To 1): Result(1, 1) = rng.Value
          Else
              Result = rng.Value
          End If
          getColumnValues = Result
      
      exitProcedure:
      End Function
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-23
        相关资源
        最近更新 更多