带有多个工作表的标准的VBA SUMIFS宏

时间:2018-01-11 14:46:33

标签: excel vba excel-vba

我一直在尝试编写一个使用SUMFIS公式的宏;这是我到目前为止:

Sub SumCodes()

Dim BL1 As Worksheet, Jan As Worksheet
Dim Code As Range, Shift As Range, Month As Range, Seconds As Range, OutPut As Range, HeadCode As Range

Set BL1 = ThisWorkbook.Sheets("BL1")
Set Jan = ThisWorkbook.Sheets("Jan")
Set Code = BL1.Range("D2:D")
Set Shift = BL1.Range("I2:I")
Set Month = BL1.Range("C2:C")
Set Seconds = BL1.Range("G2:G")
Set OutPut = Jan.Range("C3:CO3")
Set HeadCode = Jan.Range("C2:CO2")

OutPut = Application.WorksheetFunction.SumIfs(Seconds, Code, HeadCode, Month, "=Jan", Shift, "=1")

End Sub

我有大约30,000行,OutPut需要在基于输出列标题的范围内。我不想在每个单元格中输入公式,因为有很多条目。我不能附上excel工作簿,因为它太大了;但这里有一些屏幕截图:

enter image description here

enter image description here

所以我想做的是:

如果sum中的条目与工作表Column G的标题相同,我希望宏BL1 BL1 column D工作表Jan (C2)的数字BL1如果BL1中的月份(C列)是" Jan"如果set中的Shift(第一列)是1.我想最终将其更改为一年中的每个月,为3班。

当我运行代码时,我得到了一个

  

运行时错误' 1004':应用程序定义或对象定义的错误

我尝试过循环,但是我得到了同样的错误。我对VBA不太熟悉,我通常使用Python编写代码;所以我可以帮助修复这些代码,理解为什么它不起作用会非常有帮助。

提前谢谢!

1 个答案:

答案 0 :(得分:0)

考虑Excel for Windows中提供的SQL解决方案。但首先,您需要将当前宽格式的月份列调整为单独列中的原因代码,并将长格式与原因代码放在一列不同的值中。从A1单元格开始,使用各种转置程序。

Month Code Reason Code   Value
Jan   BL1          102   28242 
Jan   BL1          104       0
Jan   BL1          106       0
Jan   BL1          110       0
...

从那里运行两个工作表之间的简单聚合SQL连接查询,并将结果输出到新工作表。

SQL (在下面嵌入,根据需要调整列名称)

SELECT b.[Reason Code] As [Header_Code], b.[End Date] As [Month], 
       SUM(b.[Reason Duration (Seconds)]) As Total_Seconds
FROM [BL1$] b
INNER JOIN [JanLong$] j
   ON b.[Reason Code] = j.[Reason Code]
   AND b.[End Date] = j.[Month]
WHERE b.[Shift] = 1  AND j.[Code] = 'BL1'
GROUP BY b.[Reason Code], b.[End Date]

VBA (BL1 / 1月的SQL结果转储到现有空白标签结果中)

Sub RunSQL()    
    Dim conn As Object, rst As Object
    Dim strConnection As String, strSQL As String
    Dim i As Integer

    Set conn = CreateObject("ADODB.Connection")
    Set rst = CreateObject("ADODB.Recordset")

    ' CONNECTION STRINGS
    strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
                      & "DBQ=C:\Path\To\Workbook.xlsm;"

    strSQL = " SELECT b.[Reason Code] As [Header_Code], b.[End Date] As [Month]," _
            & "       SUM(b.[Reason Duration (Seconds)]) As Total_Seconds" _
            & " FROM [BL1$] b" _
            & " INNER JOIN [JanLong$] j" _
            & "    ON b.[Reason Code] = j.[Reason Code]" _
            & "   AND b.[End Date] = j.[Month]" _
            & " WHERE b.[Shift] = 1 AND j.[Code] = 'BL1'" _
            & " GROUP BY b.[Reason Code], b.[End Date]"

    ' OPEN CONNECTION & RECORDSET
    conn.Open strConnection
    rst.Open strSQL, conn

    ' COLUMN HEADERS
    For i = 1 To rst.Fields.Count
        Worksheets("RESULTS").Cells(1, i) = rst.Fields(i - 1).Name
    Next i        
    ' DATA ROWS
    Worksheets("RESULTS").Range("A2").CopyFromRecordset rst

    rst.Close: conn.Close    
    Set rst = Nothing: Set conn = Nothing    
End Sub

<强>可扩展性

现在要运行所有月份和所有BL,理想情况下,将所有BL *工作表附加到一个选项卡中,将所有长格式月份工作表附加到另一个选项卡中,然后运行一个主SQL语句。当然,这进一步建议使用实际的数据库。 MS Access(.accdb)数据库可以派上用场,即使没有安装Office程序,也可以在所有 Windows计算机上使用。

使用这种方法,您可以避免需要按原因代码和月份单独重新运行。但请务必在 BL_Master_Data 中添加新列以指示 BLI_Code BL1,BL2,... 。请参阅带有扩展SELECTJOINGROUP BY子句的已调整SQL:

SELECT b.[BLI_Code], b.[Reason Code] As [Header_Code], b.[End Date] As [Month], 
       SUM(b.[Reason Duration (Seconds)]) As Total_Seconds
FROM [BL_Master_Data$] b
INNER JOIN [Month_Master_Data$] m
   ON b.[Reason Code] = m.[Reason Code]
   AND b.[End Date] = m.[Month]
   AND b.[BLI_Code] = m.[Code]               -- ADDED JOIN
WHERE b.[Shift] = 1
GROUP BY b.[BLI_Code], b.[Reason Code], b.[End Date]