总和值基于唯一的ID

刚开始一份新工作。 我正在自动化一个月末报告,我是VBA的新手。 一直在成功地search我的大部分问题,但我终于碰壁了。 实质上,我正在从SAP下载一些数据,并从那里我需要build立一个报告。

我的问题是:如何在VBA中使用循环执行sumif函数?

数据拉取:Sheet1分别包含产品代码和购买金额(列A和B)。 一个产品代码可以有几个购买(几行具有相同的产品代码)。

目前为止的步骤:

  1. 我把数据表1按升序排列。

  2. 将产品代码的唯一值复制到另一个工作表(工作表2)。 所以Sheet2有一个所有产品的列表(按升序)。

  3. 我想得到sheet2栏B(每个产品代码)中所有采购的总和。 我知道如何使用公式来做到这一点,但我需要尽可能自动化。 (+我真的很想搞清楚这一点)

这是我到目前为止在VBA中所做的:Sub Macro_test()

Dim tb As Worksheet Dim tb2 As Worksheet Dim x As Integer Dim y As Integer Dim lrow As Long Set tb = Sheets("sheet1") Set tb2 = Sheets("sheet2") lrow = tb.Cells(Rows.Count, "A").End(xlUp).Row For x = 2 To lrow For y = 2 To lrow If tb2.Cells(x, 1).Value = tb.Cells(y, 1).Value Then tb2.Cells(x, 2).Value = tb.Cells(y, 2).Value End If Next y Next x 

结束小组

如果我没有弄错,对于sheet2 col A中的每个product_code,我循环遍历sheet1中的所有产品代码,找回find的LAST值,而不是所有值的总和…我明白为什么它没有不工作,我只是不知道如何解决这个问题。

任何帮助将非常感激。 谢谢!

该语句在每次迭代中覆盖tb2.Cells(x, 2).Value的值:

 tb2.Cells(x, 2).Value = tb.Cells(y, 2).Value 

相反,我认为你需要继续添加它

 tb2.Cells(x, 2).Value = tb2.Cells(x, 2).Value + tb.Cells(y, 2).Value 

但是我不喜欢双循环的外观,它只使用一个lrowvariables来表示两个不同工作表中的“最后一行”,这可能会导致一些问题。

或者,在你的循环中做这样的事情,我认为会避免重复的总和。 尽pipe如此,假设第二个工作表最初并没有任何价值

 ' Base our lRow on Sheet2, we don't care how many rows in Sheet1. lrow = tb2.Cells(tb2.Rows.Count, 1).End(xlUp).Row Dim cl as Range Set cl = tb.Cells(2,1) 'Our initial cell value / ID For x = 2 to lRow '## Look the rows on Sheet 2 '## Check if the cell on Sheet1 == cell on Sheet2 While cl.Value = tb2.Cells(x,1).Value '## Add cl.Value t- the tb2 cell: tb2.Cells(x, 2).Value = tb2.Cells(x, 2).Value + cl.Offset(0,1).Value Set cl = cl.Offset(1) '## Reassign to the next Row Wend Next 

但是最好省略双循环,并简单地使用VBA来执行以下操作之一:

1.插入公式:

(见斯科特·霍尔茨曼的回答 )。

这种方法更好些,原因很多,其中最重要的就是WorksheetFunction已经被优化了,所以它应该可以在一个小的数据集上运行得更好,但是运行时的差异是可以忽略不计的。 另一个原因是,重新发明轮子是愚蠢的,除非你有足够的理由这样做,所以在这种情况下,为什么要编写自己的代码版本来完成内置的SumIf已经做的和专门devise的?

如果参考数据可能更改,则此方法也是理想的,因为单元格公式将根据Sheet1中的数据自动重新计算。

2.评估公式并仅用数值replace:

如果您不想保留公式,则简单的Value赋值可以删除公式,但保留结果:

 With .Range(.Range("B2"), .Range("A2").End(xlDown).Offset(, 1)) .FormulaR1C1 = "=SUMIF(Sheet1!C[-1]:C[-1],RC[-1],Sheet1!C:C)" .Value = .Value 'This line gets rid of the formula but retains the values End With 

如果您要移除Sheet1,则使用此方法,因为移除参照物将会破坏Sheet2上的公式,或者如果您希望Sheet2成为“快照”而不是dynamic求和。

如果您真的需要这种自动化,请利用VBA为您提供配方。 使用R1C1表示法非常快速简单。

完整的代码(testing):

 Dim tb As Worksheet Dim tb2 As Worksheet Set tb = Sheets("sheet1") Set tb2 = Sheets("sheet2") Dim lrow As Long lrow = tb.Cells(tb.Rows.Count, 1).End(xlUp).Row tb.Range("A2:A" & lrow).Copy tb2.Range("A2") With tb2 .Range("A2").CurrentRegion.RemoveDuplicates 1 With .Range(.Range("B2"), .Range("A2").End(xlDown).Offset(, 1)) .FormulaR1C1 = "=SUMIF(Sheet1!C[-1]:C[-1],RC[-1],Sheet1!C:C)" End With End With 

请注意,对于R1C1表示法,C和R不是指列或行 字母 相反,它们是公式存储在特定工作表上的列和行偏移量。 在这种情况下, Sheet!C[-1]指的是表单1的整个A列,因为公式被input到表单2的B列中。

我写了一个整洁的小algorithm(如果你可以这么称呼的话),就是按照总计将它们分成另一个表格。 基本上它通过第一部分循环获取唯一的名称/标签,并将其存储到一个数组中。 然后,如果当前迭代匹配嵌套循环位置的当前迭代,则迭代该数组并且累加值。

 Private Sub that() Dim this As Variant Dim that(9, 1) As String Dim rowC As Long Dim colC As Long this = ThisWorkbook.Sheets("Sheet4").UsedRange rowC = ThisWorkbook.Sheets("Sheet4").UsedRange.Rows.Count colC = ThisWorkbook.Sheets("Sheet4").UsedRange.Columns.Count Dim thisname As String Dim i As Long Dim y As Long Dim x As Long For i = LBound(this, 1) To UBound(this, 1) thisname = this(i, 1) For x = LBound(that, 1) To UBound(that, 1) If thisname = that(x, 0) Then Exit For ElseIf thisname <> that(x, 0) And that(x, 0) = vbNullString Then that(x, 0) = thisname Exit For End If Next x Next i For i = LBound(that, 1) To UBound(that, 1) thisname = that(i, 0) For j = LBound(this, 1) To UBound(this, 1) If this(j, 1) = thisname Then thisvalue = thisvalue + this(j, 2) End If Next j that(i, 1) = thisvalue thisvalue = 0 Next i ThisWorkbook.Sheets("sheet5").Range(ThisWorkbook.Sheets("Sheet5").Cells(1, 1), ThisWorkbook.Sheets("Sheet5").Cells(rowC, colC)).Value2 = that End Sub 

耶arrays