【问题标题】:vba to move data to new tab, sort and subtotal excelvba将数据移动到新选项卡,排序和小计excel
【发布时间】:2018-06-08 13:01:41
【问题描述】:

感谢您的帮助-新手,但正在学习 我有一个工作表需要执行以下操作: 1.检查每个日期 2.将数据值相同的行移动到新工作表 3.将该选项卡重命名为值的mm.dd

然后为每个创建的工作表 1.按D列升序排序 2. 按第 4 列(个人电子邮件)分组第 7 列(数量)

然后显示“完成!”消息框

代码在下面,但我无法通过“个人电子邮件”的名字完成它 不胜感激!
链接以查看所需结果 - desired result 链接看起点-starting point

Sub TransferReport()
Dim WS      As Worksheet
Dim LastRow As Long

'Check each date
 For Each DateEnd In Sheet1.Columns(3).Cells
    If DateEnd.Value = "" Then Exit Sub 'Stop program if no date
    If IsDate(DateEnd.Value) Then
        shtName = Format(DateEnd.Value, "mm.dd")    'Change date to valid tab name

        On Error GoTo errorhandler  'if no Date Sheet, go to errorhandler to create new tab
        If Worksheets(shtName).Range("A2").Value = "" Then
           DateEnd.EntireRow.Copy Destination:=Worksheets(shtName).Range("A2")
           Worksheets(shtName).Range("A1:M1").Columns.AutoFit
        Else
            DateEnd.EntireRow.Copy Destination:=Worksheets(shtName).Range("A1").End(xlDown).Offset(1)
        End If
    End If
Next

Exit Sub
errorhandler:
Sheets.Add After:=Sheets(Sheets.Count) 'Create new tab
ActiveSheet.Name = shtName  'Name tab with date
Sheet1.Rows(1).EntireRow.Copy Destination:=ActiveSheet.Rows(1) 'Copy heading to new tab
Resume

'SortAllSheets()
   'Ascending sort on A:M using column D, all sheets in workbook
   For Each WS In Worksheets
      WS.Columns("A:M").Sort Key1:=WS.Columns("D"), Header:=xlYes, Order1:=xlAscending
   Next WS

 'SubTotals()
    For Each WS In Worksheets
                    With wsDst
                 LastRow = .Range("A" & Rows.Count).End(xlUp).Row
                .Range("A1:M" & LastRow).Subtotal GroupBy:=4, Function:=xlSum, TotalList:=Array(7), Replace:=True, PageBreaks:=False, SummaryBelowData:=True
            End With
        Next

在图片和所需结果之前添加图像: 图片前 - before data

图片后-desired result

【问题讨论】:

  • 每次运行代码时,如果 Sheet1 列 C 中的数据是日期,则创建工作表并复制数据,或者如果工作表已存在,则从 Sheet1 复制行。如果您多次运行代码,则会复制重复的数据。排序和小计不起作用,至少部分是因为 for each 循环是错误的。但是完全不清楚你想要达到什么目的。如果您可以添加一些细节以了解您的目标,那将会很有帮助。还要考虑到,在您的代码中,具有相同日期/月份但不同年份的数据最终会出现在同一张表中,并且对年份的引用将丢失。
  • @cmarg 我已附加到源文档和所需结果的链接。到原来的帖子。我认为这可能会有所帮助 - 感谢您的关注 -
  • 请上传起点和期望结果的截图。这个任务有一个链接。我从不打开在线文件...
  • @cMarg 我已添加屏幕截图并删除了文件 - 堆栈溢出不允许屏幕打印 - 将鼠标悬停在链接上,您可以看到它们是 .png 文件 - 谢谢!
  • 因此,将行传输到新工作表并在必要时创建它们的代码有效吗? (如果您希望多次运行它并避免重复,它可以从删除除了 sheet1 之外的所有工作表(如果有)开始)。您想对 Sheet1 以及按日期组织的那些进行排序和小计吗?看起来它会按照当前的编码尝试这样做。

标签: excel sorting copy subtotal vba


【解决方案1】:

试试这个。我不喜欢在错误时添加工作表,因为它会在出现错误时添加工作表。因此,以下代码扫描所有工作表,并将它们添加到数组中。在循环中,找到日期后,检查工作表名称是否已存在。请记住,每次运行代码时代码都会添加数据(因此会有重复的数据)。不同年份但同一天/月的数据也将收集在一起,不参考年份。

如果你想保留你的代码,请注意:

1)Exit Sub 不允许执行您的其余代码。

2)For Each WS In Worksheets有错误的sintax

3) Worksheets(shtName).Range("A1:M1").Columns.AutoFit 只考虑 Autofit 的第一行

4) If DateEnd.Value = "" Then Exit Sub 如果中间有一个没有日期的单元格,将退出代码

Sub TransferReport()
Dim WS As Worksheet
Dim MainSheet As Worksheet
Dim LastRow As Long
Dim DateEnd As Range
Dim NextLastRow As Long
Dim i As Long
Dim ArraySheets() As String
Dim shtName As String


'Store sheet names in array
ReDim ArraySheets(1 To Sheets.Count)
For i = 1 To ThisWorkbook.Sheets.Count
        ArraySheets(i) = ThisWorkbook.Sheets(i).Name
Next

'Check each date
Set MainSheet = ThisWorkbook.Worksheets("Sheet1")
LastRow = MainSheet.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To LastRow
    If IsDate(MainSheet.Cells(i, 3).Value) Then
        shtName = Format(MainSheet.Cells(i, 3).Value, "mm.dd")
        If Not IsInArray(shtName, ArraySheets) Then
            With ThisWorkbook
                Set WS = .Sheets.Add(After:=.Sheets(.Sheets.Count)) 'Create new tab
                WS.Name = shtName 'Name tab with date
                MainSheet.Rows(1).EntireRow.Copy Destination:=WS.Rows(1) 'Copy heading to new tab
                ArraySheets(UBound(ArraySheets)) = shtName
                ReDim Preserve ArraySheets(1 To UBound(ArraySheets) + 1) As String 'add new sheet name to array
            End With
        End If

        NextLastRow = Worksheets(shtName).Cells(Rows.Count, 1).End(xlUp).Row + 1
        MainSheet.Rows(i).EntireRow.Copy Destination:=Worksheets(shtName).Cells(NextLastRow, 1)
        Worksheets(shtName).Columns("A:M").Columns.AutoFit
    End If
Next

'   'Ascending sort on A:M using column D, all sheets in workbook
   For Each WS In ActiveWorkbook.Worksheets
      WS.Columns("A:M").Sort Key1:=WS.Columns("D"), Header:=xlYes, Order1:=xlAscending
      LastRow = WS.Range("A" & Rows.Count).End(xlUp).Row
      WS.Range("A1:M" & LastRow).Subtotal GroupBy:=4, Function:=xlSum, TotalList:=Array(7), Replace:=True, PageBreaks:=False, SummaryBelowData:=True
   Next WS

End Sub

Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
    IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function

编辑

看来你要举报。我通常对分组感到不舒服,并且喜欢明确说明我想要什么。当然这是个人喜好。但如果你也是这种情况,请尝试下面的代码。每次运行宏时,都会删除报告表并创建新表。主工作表("Sheet1")也没有修改。这样您就可以更好地控制输出。

Dim WS As Worksheet
Dim MainSheet As Worksheet
Dim LastRow As Long
Dim DateEnd As Range
Dim NextLastRow As Long
Dim i As Long
Dim ArraySheets() As String
Dim shtName As String
Dim TheRow As Long
Dim TheSum As Variant
Dim WSName As Variant, TheCustomerMail As String


'Store Main sheet name in array
ReDim ArraySheets(1 To 1)
ArraySheets(1) = ActiveWorkbook.Worksheets("Sheet1").Name

'Delete all previous sheets, except main one ("Sheet1")
Application.DisplayAlerts = False
For i = ThisWorkbook.Sheets.Count To 1 Step -1
    If Sheets(i).Name <> "Sheet1" Then
        ThisWorkbook.Sheets(i).Delete
    End If
Next
Application.DisplayAlerts = True

'Check each date
Set MainSheet = ActiveWorkbook.Worksheets("Sheet1")
LastRow = MainSheet.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To LastRow
    If IsDate(MainSheet.Cells(i, 3).Value) Then
        shtName = Format(MainSheet.Cells(i, 3).Value, "mm.dd")
        If Not IsInArray(shtName, ArraySheets) Then
            With ThisWorkbook
                Set WS = .Sheets.Add(After:=.Sheets(.Sheets.Count)) 'Create new tab
                WS.Name = shtName 'Name tab with date
                MainSheet.Rows(1).EntireRow.Copy Destination:=WS.Rows(1) 'Copy heading to new tab
                ReDim Preserve ArraySheets(1 To UBound(ArraySheets) + 1) As String
                ArraySheets(UBound(ArraySheets)) = shtName
            End With
        End If

        NextLastRow = Worksheets(shtName).Cells(Rows.Count, 1).End(xlUp).Row + 1
        MainSheet.Rows(i).EntireRow.Copy Destination:=Worksheets(shtName).Cells(NextLastRow, 1)
        Worksheets(shtName).Columns("A:M").Columns.AutoFit
    End If
Next

'Ascending sort on A:M using column D, all sheets in workbook
For Each WSName In ArraySheets
    TheCustomerMail = "" 'Starting name
    TheSum = ""

    If WSName <> "Sheet1" Then 'Only sort "new" sheets, not main one
        Worksheets(WSName).Columns("A:M").Sort Key1:=Worksheets(WSName).Columns("D"), Header:=xlYes, Order1:=xlAscending
        LastRow = Worksheets(WSName).Range("A" & Rows.Count).End(xlUp).Row
        TheRow = LastRow + 1
        For i = LastRow To 1 Step -1
            If i = 1 Then
                Worksheets(WSName).Cells(TheRow, 5) = TheSum
            Else
                If Worksheets(WSName).Cells(i, 4).Value <> TheCustomerMail Then
                    Worksheets(WSName).Cells(TheRow, 5) = TheSum
                    Worksheets(WSName).Rows(i + 1).Insert shift:=xlShiftDown
                    Worksheets(WSName).Rows(i + 1).Insert shift:=xlShiftDown
                    TheRow = i + 1
                    TheSum = Worksheets(WSName).Cells(i, 5).Value
                    TheCustomerMail = Worksheets(WSName).Cells(i, 4).Value
                    'Worksheets(WSName).Rows(i + 1).Columns("A:M").Interior.ColorIndex = 16
                    'Worksheets(WSName).Rows(i + 1).Columns("A:M").Font.ColorIndex = 2
                    Worksheets(WSName).Rows(i + 1).Columns("A:M").Font.Bold = True
                    Worksheets(WSName).Cells(i + 1, 4) = "Total of " & TheCustomerMail & ":"
                    Worksheets(WSName).Columns("D").Columns.AutoFit
                Else
                    TheSum = TheSum + Worksheets(WSName).Cells(i, 5).Value
                End If
            End If
        Next
    End If
Next

End Sub

Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
    IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function

【讨论】:

  • 运行代码,但下标超出范围错误。
  • 哪一行?可以按F8启动宏,一步一步走。
  • 你是对的。我不是专家。昨天代码可以工作,但今天我遇到了问题。但是,我将数据和宏复制到了一个新的 excel 文件中,现在它可以工作了(在 Siddharth Rout here 发表评论之后)。我还注意到,如果您想再次运行代码,则必须在订购之前摆脱分组。
  • 用 activeworkbook 替换了“thisworkbook”,它就像一个魅力!我应该在我的问题中指定,谢谢! -
猜你喜欢
  • 1970-01-01
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 2013-11-24
  • 2017-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多