【问题标题】:VBA SUMIFS Macro with Criteria from multiple worksheets带有来自多个工作表的条件的 VBA SUMIFS 宏
【发布时间】:2018-01-12 03:34:54
【问题描述】:

我一直在尝试编写一个使用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 工作簿,因为它太大了;但这里有几个屏幕截图:

所以我想做什么:

如果BL1 column D 中的条目与工作表Jan (C2) 的标题相同并且如果月份(C 列)在BL1 是“Jan”,如果 BL1 中的 Shift(第 I 列)为 1。我最终希望将其更改为一年中的每个月,进行 3 个轮班。

当我运行我拥有的代码时,我得到一个

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

我试过循环,但我得到了同样的错误。我对 VBA 不是很熟悉,我通常用 Python 编写代码;因此,我可以在修复此代码并理解它为什么不起作用的方式上获得的任何帮助都会非常有帮助。

提前谢谢你!

【问题讨论】:

  • "D2:D" 不是有效范围。您可以使用整个列 "D:D" 或添加结束行号。其他列也一样。
  • 好吧,我明白为什么会这样了。所以对于' C3:CO3 '和' C2:CO2 '我必须将它用作循环吗?当我删除行索引并填写 100,000 个条目时,我没有考虑清楚。

标签: vba excel


【解决方案1】:

考虑在 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_CodeBL1, 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]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多