我一直在尝试编写一个使用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工作簿,因为它太大了;但这里有一些屏幕截图:
所以我想做的是:
如果sum
中的条目与工作表Column G
的标题相同,我希望宏BL1
BL1 column D
工作表Jan (C2)
的数字BL1
如果BL1
中的月份(C列)是" Jan"如果set
中的Shift(第一列)是1.我想最终将其更改为一年中的每个月,为3班。
当我运行代码时,我得到了一个
运行时错误' 1004':应用程序定义或对象定义的错误
我尝试过循环,但是我得到了同样的错误。我对VBA不太熟悉,我通常使用Python编写代码;所以我可以帮助修复这些代码,理解为什么它不起作用会非常有帮助。
提前谢谢!
答案 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,... 。请参阅带有扩展SELECT
,JOIN
和GROUP 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]