我可以使小计宏更有效吗?

时间:2016-01-24 20:24:06

标签: excel excel-vba vba

我有一张表格,其中数据以下面的格式粘贴。我需要计算每个月有一个条目的次数,正如您从下面的示例中可以看到的那样,它可以在一个月内的许多天发生。

我能想到的唯一方法是将月份分开并对其进行小计并复制总数。

麻烦的是由于数据量的原因需要花费很长时间才能运行。

还有其他方法可以解决这个问题吗?我已粘贴下面的当前代码。 TIA

enter image description here

' Add Totals

Sheets("Data").Select
Columns("G:G").Select
Selection.NumberFormat = "mm"
Range("F4").Select
Selection.Subtotal GroupBy:=7, Function:=xlCount, TotalList:=Array(7), _
    Replace:=True, PageBreaks:=False, SummaryBelowData:=True
ActiveSheet.Outline.ShowLevels RowLevels:=2
Range("G3:G4000").Select
    Selection.SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Sheets("Set Up Data").Select
Range("B2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Sheets("Data").Select
Range("D56").Select
Application.CutCopyMode = False
Selection.RemoveSubtotal

5 个答案:

答案 0 :(得分:2)

将数据复制到变量数组会更快,并对其进行分析。

像这样的东西

Sub Demo()
    Dim rData As Range
    Dim vData As Variant
    Dim i As Long
    Dim Counts(1 To 12, 1 To 1) As Long

    ' Get range reference to source data
    '   assumes data is in column G, starting at row 4.  Adjust as required
    With Worksheets("Data")
        Set rData = .Range(.Cells(4, 7), .Cells(.Rows.Count, 7).End(xlUp))
    End With

    ' copy range data to variant array
    vData = rData.Value

    ' count occurance of each month
    For i = 1 To UBound(vData, 1)
        ' allow for possibility that dates are actually strings
        Counts(Month(CDate(vData(i, 1))), 1) = Counts(Month(CDate(vData(i, 1))), 1) + 1

    Next

    ' put count data back on sheet
    '   adjust target as required
    Worksheets("Set Up Data").Cells(2, 2).Resize(UBound(Counts, 1), 1) = Counts

End Sub

答案 1 :(得分:0)

我还可以考虑其他两种方式,但两种方式都会在不同的表格中显示答案:

  1. 使用数据透视表
  2. 使用PowerQuery - 现在内置于Excel 2016,但它是2010/2013的免费Microsoft插件。

答案 2 :(得分:0)

有点hacky但应该比你拥有的更快。我假设您知道最短日期和最长日期。

首先添加一个连接月份和年份的新列。例如,2016年1月24日,列值将是2016年1月。循环遍历工作表以为每行添加此列。现在,您执行第二个循环,此时循环开始月和结束月之间的日期,并在循环中计算工作表的月 - 年字符串列中每个连接字符串的出现次数。因此,如果第一个月是2015年2月,则计算该列中2015年2月的出现次数,然后在下一次迭代中计算2015年3月的数量,依此类推。最后,您按月计算,并删除额外的列。

答案 3 :(得分:0)

你可以随时使用公式方法:

enter image description here

设置表后,我使用了COUNTIF()公式:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>

int main(void) {
    int     fd[2];
    pid_t   childpid;
    char    input = 'o';

    pipe(fd);

    if ((childpid = fork()) == -1) {
        perror("fork");
        exit(1);
    }

    if (childpid == 0) {
        close(0);
        dup(fd[0]);
        execl("draw.out", "draw.out", NULL);
    } else {
        close(fd[0]);
        initscr();
        while (input != 'q') {
            read(0, &input, 1);
            if (input == 'a' || input == 's' || input == 'd' || input == 'w' || input == 'q') {
                write(fd[1], &input, 1);
            }
        }
        endwin();
        exit(0);
    }

    return 0;
}

或者您可以使用SUMPRODUCT():

=COUNTIFS(G:G,"<"&DATE(K2,J2+1,1),G:G,">=" &DATE(K2,J2,1))

这只是一个FYI。

答案 4 :(得分:-1)

请您试试以下代码吗?我刚刚发布了你发布的一些内容。数据必须按加入日期排序才能生效。

Sub testSubtotal()
  Sheets("Data").Select
  Columns("G:G").Select
  ' Since you have two different years in the example I think it would be
  ' better to get subtotals for year and month together
  Selection.NumberFormat = "yyyy-mm"
  Range("F1").Select
  Selection.Subtotal GroupBy:=7, Function:=xlCount, TotalList:=Array(7), _
      Replace:=True, PageBreaks:=False, SummaryBelowData:=True
  ActiveSheet.Outline.ShowLevels RowLevels:=2

  ' Selecting also column F you will get the description of the subtotal
  ' in the "Set Up Data" worksheet
  Range("F1:G4000").Select
  Selection.SpecialCells(xlCellTypeVisible).Copy
  Sheets("Set Up Data").Select

  ' I have changed the destination cell to B1
  ' but I do not know how yor worksheet is formatted.
  Range("B1").Select
  ActiveSheet.Paste
  Sheets("Data").Select
  Cells.Select
  Selection.RemoveSubtotal
End Sub

我只在一张数据很少的桌子上测试过它,但它看起来并不慢。我希望我能正确理解你的问题...