如何使用VBA宏在excel表格中查找条件累积和

如何使用VBA宏在excel表格中查找条件累积和,vba,excel,Vba,Excel,假设我有两列 3.5463 11 4.5592 12 1.6993 111 0.92521 112 1.7331 121 2.1407 122 1.4082 1111 2.0698 1112 2.3973 1121 2.4518 1122 1.1719 1211 1.153 1212 0.67139 1221 0.64744 1222 1.3705 11111 0.9557 11112 0.64868 11121 0.7325 11211 0.58874 1121

假设我有两列

3.5463  11
4.5592  12
1.6993  111
0.92521 112
1.7331  121
2.1407  122
1.4082  1111
2.0698  1112
2.3973  1121
2.4518  1122
1.1719  1211
1.153   1212
0.67139 1221
0.64744 1222
1.3705  11111
0.9557  11112
0.64868 11121

0.7325  11211
0.58874 11212
0.86673 11221
0.17075 11222
0.64026 12111
0.80229 12112

0.43422 12122
1.0405  12211
0.63376 12212
0.56491 12221
0.34626 12222
0.81631 111111
0.91837 111112
0.70013 111121
0.87384 111122
1.1474  111211

0.47411 111221
0.12249 111222
0.56728 112111
0.88169 112112
0.14509 112121

0.68655 112211
0.36274 112212


1.1652  121111
0.99314 121112
0.42024 121121
0.23937 121122




1.0346  122111
0.64642 122112
0.15632 122121
0.41725 122122
0.40793 122211
在第一列中,有一个数字。第二列中的每一个数字都有一个相关的ID。现在,有些空行中不包含任何数字

如果第一个数字的ID与第二个数字的ID相同,且末尾有一个额外数字,则将其中一个数字定义为另一个数字的子数字。例如,ID 11211和11212都是1121的子项,因为1121的ID在末尾添加了一个额外的数字,即1或2,以形成其子项的ID。因此,1121是11211和11212的父级

下面是我希望宏执行的操作。它必须输出第三列,每行包含该行第一列的编号的累积和,加上该编号的父编号,以及父编号的父编号,等等,直到它达到11或12为止。它将首先简单地输出第1列中11和第3列中12的数字。然后,在一个以111开头的循环中,它将把每一行的累积和(该行中的数字加上父行的第三列输出)相加,前提是该行有一个数字和一个id,并且父行存在并且在第3列中有一个输出。例如,ID为11222的行的第3列中的数字应该是该行第1列中的数字,加上1122的数字,加上112的数字,再加上11的数字。因此,0.17075+2.4518+0.92521+3.5463或7.09406。但是,如果您尝试对ID 111221执行此操作,您将注意到父11122应该位于的行是空的。因此,父项不存在,对于111221,在第3列中不会输出任何值

如果有人有时间为我编写这个VBA宏,以换取一个可接受的解决方案,我将不胜感激


谢谢

我认为不需要宏,只需要一些公式。首先,我在数据列(如value和id)上放置一个标题。如果然后突出显示列标签,即a和B,然后按B id排序,然后按值排序,则将空行分组。然后可以删除这些行。现在,您几乎已经准备好了数据。当我这样做时,我将id列转换为文本,而不是数字值,因此如果我按id对表进行排序,模式将是11、111、1111等等,而不是11、12、111、112、121。然后,我添加了列来分隔ID的各个字符或级别。这是为了帮助父母和孩子。您可以使用文本到列,或者使用中间公式,但我所做的是在右侧增加6列。对于每个id行,每列都有1、2或空空值。然后我添加了另一列,称之为level。我在所有id拆分列中都使用了类似COUNTA的公式。所以,对于11,我的水平值是2。111是311221是5,依此类推。这将为我提供id级别的父、子、孙等。然后我将最后一列添加到右侧,以计算值的累积和。在概念上,我有一个大的嵌套IF语句,但在实践中,我需要两个。我的公式是,如果我上面的行有一个较低的级别编号,即它是某种父级,则将当前行的值与上面行的值相加。否则,继续向上移动一行,直到得到一个父行,并将当前行值添加到该数字

除前5行数据外,我的最后一个公式是在第6行数据中:
=如果k6其余答案如下

=if(K6<K7,L6+C7,if(K5<K7,L5+C7,if(K4<K7,L4+C7,if(K3<K7,L3+C7,if(K2<K7,L2+C7,C7)))))
例如,ID为11222的行的第3列中的数字应该是该行第1列中的数字,加上1122的数字,加上112的数字,再加上11的数字。因此,0.17075+2.4518+0.92521+3.5463或7.09406。但是,如果您尝试对ID 111221执行此操作,您将注意到父11122应该所在的行是空的。因此,父项不存在,对于111221,在第3列中不会输出任何值

作为D1中的本机工作表数组公式

=IF(LEN(B1), SUM(SUMIFS(A$1:INDEX(A:A, MATCH(1E+99, A:A)), 
     B$1:INDEX(B:B, MATCH(1E+99, A:A)), LEFT(B1, ROW(INDIRECT("2:"&LEN(B1)))))), TEXT(,))
以上内容不能补偿缺少的父null字符串。它汇总了所有能找到的数据,并用零表示失踪的父母

作为E1中的VBA UDF²

Function conditionalCumulativeSum(nums As Range, _
        ids As Range, sib As Range, _
        Optional nullOnBlank As Boolean = True)
    Dim i As Integer

    'truncate any full column reference to the UsedRange
    Set nums = Intersect(nums, nums.Parent.UsedRange)

    'match the nums and ids ranges
    Set ids = ids.Resize(nums.Rows.Count, nums.Columns.Count)

    For i = Len(sib.Value2) To 2 Step -1
        If nullOnBlank And IsError(Application.Match(--Left(sib, i), ids, 0)) Then
            conditionalCumulativeSum = vbNullString
            Exit For
        End If
        conditionalCumulativeSum = conditionalCumulativeSum + _
            Application.SumIfs(nums, ids, Left(sib, i))
    Next i

    If i = 0 Then conditionalCumulativeSum = vbNullString
End Function
当通过遗传链遇到任何缺失的父项时,上面的默认值将返回空字符串。这可以通过添加FALSE作为可选的第四个参数来关闭,然后UDF的行为将与本机公式相同

从样本数据

imk_数组公式需要使用Ctrl+Shift+Enter完成↵. 如果输入正确,Excel会将公式用大括号括起来,例如{和}。您自己不需要键入大括号。正确输入第一个单元格后,可以像任何其他公式一样填充或向下或向右复制它们。尝试将整列引用减少到更接近实际数据范围的范围。数组公式以对数方式占用计算周期,因此缩小引用范围是一种很好的做法 最大限度地减少了辐射范围。有关更多信息,请参阅


²将用户定义的功能(又称UDF)放入标准模块代码表中。点击Alt+F11,当VBE打开时,立即使用下拉菜单插入► 模块Alt+I,M。将功能代码粘贴到新的模块代码表中,标题类似于Book1-Module1代码。点击Alt+Q返回工作表。

欢迎使用SO。不幸的是,这不是一个免费的代码平台。一般来说,用户会希望您提出自己的解决方案的一部分,或者您无法解决的问题的一个非常具体的部分,而不是您希望从零开始为您编写的问题定义。依我看,在excelforums.com这样的网站上,你有更好的机会,用户可以这样做。或者,更好的是,启动一个自己的脚本,如果您有任何具体问题,请返回给我们-我们很乐意在这一点上提供帮助。只是一个提示..尝试SUMIF函数..老实说,虽然这对于VBA来说还不够复杂,但它并不像简单的SUMIF那样容易以可接受的方式解决它。使用类似于{=SUMSUMIFB$2:B4,1*LEFTB4,ROWA$2:INDEXA:A,LENB4,A$2:A4}的方法确实有效,但是每增加一行数据,计算时间就会大大增加。即使只是一个例子,也可能会让它冻结一段时间。同样,像{=SUMIFB$2:B4=TRANSPOSE1*LEFTB4,ROWA$2:INDEXA:a,LENB4,a$2:A4}这样的普通数组也可以实现这一点。如果不使用辅助列来解决它,则不使用数组formulas@DirkReichel-我已经制定了一个本机数组公式和一个UDF,用于等待OP显示效果,但公式仍然缺少OP的最终条件。也就是说:如果链中的任何父级不存在,则返回一个空字符串,该字符串在第二段到最后一段末尾描述。UDF不难做到这一点,但我放弃了数组公式。至于使用数组公式,像这样的ID编号系统,可能会有多少条记录?@Jeeped我完全错过了。。。那么根本不需要数组:D
=IF(LEN(B1), SUM(SUMIFS(A$1:INDEX(A:A, MATCH(1E+99, A:A)), 
     B$1:INDEX(B:B, MATCH(1E+99, A:A)), LEFT(B1, ROW(INDIRECT("2:"&LEN(B1)))))), TEXT(,))
Function conditionalCumulativeSum(nums As Range, _
        ids As Range, sib As Range, _
        Optional nullOnBlank As Boolean = True)
    Dim i As Integer

    'truncate any full column reference to the UsedRange
    Set nums = Intersect(nums, nums.Parent.UsedRange)

    'match the nums and ids ranges
    Set ids = ids.Resize(nums.Rows.Count, nums.Columns.Count)

    For i = Len(sib.Value2) To 2 Step -1
        If nullOnBlank And IsError(Application.Match(--Left(sib, i), ids, 0)) Then
            conditionalCumulativeSum = vbNullString
            Exit For
        End If
        conditionalCumulativeSum = conditionalCumulativeSum + _
            Application.SumIfs(nums, ids, Left(sib, i))
    Next i

    If i = 0 Then conditionalCumulativeSum = vbNullString
End Function