【问题标题】:Code to help consolidate last column used across multiple tabs帮助合并跨多个选项卡使用的最后一列的代码
【发布时间】:2021-09-29 03:48:15
【问题描述】:

我有一系列电子表格,我们使用这些电子表格将参数加载到数据库中,以实现点击式订单输入。一些电子表格有数百张工作表,保持最新状态一直是个问题。我要做的是插入一些代码,这些代码将逐页进行,并将每个选项卡中的一些数据编译到摘要表中。

我已经修改了来自Excel VBA to insert sheet name on each row when combining data tables with variable columns 的代码,但我是个彻头彻尾的黑客,到目前为止还没有成功。

简而言之,我需要代码来返回 A 列中的工作表名称,然后扫描第一行以查找第一个未使用的列,然后将该列的内容返回到 C 列和它来自的行#汇总表上的 B 列。

此示例说明了数据的结构,一系列问题,最后有答案。它们不是静态的,但问题在第 1 行有标题(有时只是一个空格值),但答案没有,该列的单元格 1 始终为空白(null)。

编辑:使用 Stack Overflow 上的多个资源,我设法将它拼凑在一起,几乎可以正常工作。我需要找到带有空标题的第一列(第 1 行)和任何中断之前的最后一行,而不是找到最后使用的列和行。这是因为在数据右侧和可能下方的大多数工作表中添加了注释。

Sub CopyData()
    Application.ScreenUpdating = False
    Dim wsSummary As Worksheet
    Dim LastRowWs As Long
    Dim LastColWs As Long
    Dim LastRowSummary As Long
    Dim StartRowSummary As Long
    Set wsSummary = ThisWorkbook.Worksheets("Summary") ' defines WsSummary
    LastRowSummary = wsSummary.Cells(wsSummary.Rows.Count, "A").End(xlUp).Row + 1 ' identifys the last used row on target summary sheet
    wsSummary.Range("A2:ZZ" & LastRowSummary).Clear 'clears a set range on target summary sheet
    For Each Ws In ThisWorkbook.Worksheets
        Select Case Ws.Name
            Case "Summary", "Category", "TOC", "Index"
                'If it's one of these sheets, do nothing
            Case Else
            LastRowWs = Ws.Cells(Ws.Rows.Count, "A").End(xlUp).Row ' Finds the last column in worksheet
            LastColWs = Ws.Cells(LastRowWs, Columns.Count).End(xlToLeft).Column ' Finds the last used colun in Worksheet - ISSUE, I need first null cell column!
            StartRowSummary = wsSummary.Cells(wsSummary.Rows.Count, "A").End(xlUp).Row + 1 'first empty row
            Ws.Range(Split(Cells(, LastColWs).Address, "$")(1) & "2:" & Split(Cells(, LastColWs).Address, "$")(1) & LastRowWs).Copy Destination:=wsSummary.Range("A" & StartRowSummary)
            LastRowSummary = wsSummary.Cells(wsSummary.Rows.Count, "A").End(xlUp).Row
            wsSummary.Range("B" & StartRowSummary & ":B" & LastRowSummary) = Ws.Name ' returns sheet name
            wsSummary.Range("C" & StartRowSummary & ":C" & LastRowSummary) = LastColWs 'returns column #
            wsSummary.Range("D" & StartRowSummary & ":D" & LastRowSummary) = Split(Cells(, LastColWs).Address, "$")(1) 'returns Column letter
        End Select
    Next
    Application.ScreenUpdating = True
End Sub

【问题讨论】:

  • 请告诉我们你自己尝试了什么。 How to ask.
  • 我将编辑我的原始帖子。
  • 您的代码与您要做什么的描述不符?例如。 ColB 与 ColA 中的工作表名称,源 Row# 与源 Col#... 通常,“行”和“列”之间存在很多混淆,因此很难理解。

标签: excel vba


【解决方案1】:

试试这个 - 稍微拆分一下逻辑,让它更容易理解......

Sub CopyData()
    
    Dim wsSummary As Worksheet
    Dim LastRowWs As Long
    Dim LastColWs As Long
    Dim LastRowSummary As Long
    Dim StartRowSummary As Long, copyRange As Range, nextRow As Long
    Dim copyRows As Long, colLetter, ws As Worksheet
    
    Application.ScreenUpdating = False
    
    Set wsSummary = ThisWorkbook.Worksheets("Summary") ' defines WsSummary
    LastRowSummary = wsSummary.Cells(wsSummary.Rows.Count, "A").End(xlUp).Row + 1
    wsSummary.Range("A2:ZZ" & LastRowSummary).Clear 'clears a set range on target summary sheet
    
    nextRow = 2                              'start pasting here
    For Each ws In ThisWorkbook.Worksheets
        If ProcessThisSheet(ws) Then         'use this sheet ?
            Set copyRange = GetCopyRange(ws) 'find something to copy
            If Not copyRange Is Nothing Then
                copyRows = copyRange.Cells.Count
                colLetter = Split(copyRange.EntireColumn.Address(0, 0), ":")(0)
                With wsSummary.Rows(nextRow)
                    copyRange.Copy .Cells("A")
                    .Columns("B").Resize(copyRows).Value = ws.Name
                    .Columns("C").Resize(copyRows).Value = copyRange.Column
                    .Columns("C").Resize(copyRows).Value = colLetter
                End With
                nextRow = nextRow + copyRows
            End If
        End If
    Next
    Application.ScreenUpdating = True
End Sub

'find the range of cells to copy from (returns Nothing if no suitable range located)
Function GetCopyRange(ws As Worksheet) As Range
    Dim c As Range, c2 As Range, rv As Range
    Set c = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Offset(1, 1) 'cell below the empty header cell
    If c.Column = 2 Or Len(c.Value) = 0 Then Exit Function 'on Col2 so row1 was empty, or no value below the empty header
    If Len(c.Offset(1, 0).Value) > 0 Then
        Set GetCopyRange = ws.Range(c, c.End(xlDown)) 'down to end of data
    Else
        Set GetCopyRange = c 'just 1 cell to copy
    End If
End Function

'work with `ws` ?
Function ProcessThisSheet(ws As Worksheet)
    Select Case ws.Name
        Case "Summary", "Category", "TOC", "Index"
            ProcessThisSheet = False
        Case Else
            ProcessThisSheet = True
    End Select
End Function

【讨论】:

  • 蒂姆,感谢您的回复!很抱歉原始代码“混乱”,我知道编码时很危险。我倾向于有一个需求,然后在我试图完成任务时自学我需要知道的东西,然后回到我的其他 11 份工作。 :) 您的代码在没有返回任何内容的情况下运行到摘要页面,然后在 GetCopyRange 函数的If c.Column = 2 Or Len(c.Value) = 0 Then Exit Function 上崩溃。有没有办法让我将我的实际电子表格发送给您?
  • 在 gmail dot com 向您发送了样本
  • 压缩后重新发送
【解决方案2】:

您是否考虑过制作表格、表格并将它们关联起来?

如果您正在组合具有 ID 关系的数据,即使它们跨越数千张工作表,您也可以使用“插入”选项卡将它们设置为带有正确标题的表,在“数据”选项卡中关联它们,然后在 Power Pivot/Query 中将它们组合在一起,一旦完成,您就可以在 Power Query 上执行获取最后一行的操作,然后您无需编写任何代码,或者一个更好的链接到该 Power Pivoted Table 作为表实例,并让您的系统获取最后一行或多行(只需更改号码)。

  SELECT TOP 1 FROM tblResult ORDER BY ID DESC

【讨论】:

  • 感谢您的回复。不幸的是,编辑现有工作表不是一种选择。电子表格中内置了一个宏,可将所有特定格式的数据加载到我们数据库的一个区域中,以创建点击系统。
  • 您可以引用现有数据作为数据源,而无需实际接触它。一旦加载到合并表中,您就可以形成关系并执行您的指标:) 我的意思是宏对系统很好,但真正的力量是 ETL 命中刷新,让它们都从它们的连接中加载而不实际打开任何东西。
猜你喜欢
  • 2020-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
  • 2012-05-10
  • 1970-01-01
相关资源
最近更新 更多