在Excel中对包含排除项的'sumif'进行排序

wmvff8tz  于 2022-11-18  发布在  其他
关注(0)|答案(1)|浏览(268)

我有自动计算每个项目损益的工作表。目前他们使用的是固定工资,但我想改变它,以纳入任何未来的工资变化。项目持续时间是从L1排序的,基于E2中的持续时间参数,使用=EDATE($C$2, SEQUENCE(1, $E$2, 0))
列L中的每个单元格按顺序遍历持续时间,计算相关值。

工资成本的公式引用下面的数据集,该数据集也是使用=FILTER(FILTER(AllStaffProjectAllocationTbl,AllStaffProjectAllocationTbl[Project Code Name]=B2), {1,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0})从另一个工作表中的数据自动生成的,并且可以具有可变的条目数:

L7中计算工资成本的当前公式(来自第一张图片)是=MMULT(SEQUENCE(1,ROWS($A$18#),1,0),($L$1#>=OFFSET($A$18#,0,3,,1))*($L$1#<=OFFSET($A$18#,0,4,,1))*OFFSET($A$18#,0,5,,1)),它使用了第二张图片中的F列(我希望删除它)。
我在表EmployeeSalaryTbl中得到了一组新的工资数据(为了确保下面的计算正常进行,我必须添加一个虚构的结束日期31/12/9999。理想情况下,这应该是空白的,我将在下面的计算中检查它):

我已经开始修改L7中的MMult函数,以执行以下操作:
1.项目工期顺序
1.检查从A18开始的员工是否参与了从L1开始的给定月份的项目
1.如果是,则从EmployeeSalaryTbl中查找日期范围内的薪金,并将该月的薪金相加。
这是我目前所拥有的,但不幸的是,它给了我一个错误:
=MMULT(SEQUENCE(1,ROWS($A$18#),1,0),IF(AND(($L$1#>=OFFSET($A$18#,0,3,,1))*($L$1#<=OFFSET($A$18#,0,4,,1))),SUMIFS(EmployeeSalaryTbl[Salary Monthly], EmployeeSalaryTbl[Employee],$A$18#, EmployeeSalaryTbl[Salary Start Date],"<="&$L$1#, EmployeeSalaryTbl[Salary End Date],">="&$L$1#),0))
图2定义的项目数据为:
| 员工|角色|专业|开始日期|结束日期|月薪|
| - -|- -|- -|- -|- -|- -|
| 鲍勃|高级程序员|程序设计|2020年1月12日|2020年6月5日|4,333英镑|
| 戴夫|中级程控仪|程序设计|2020年2月1日|2020年5月30日|3,167英镑|
| 彼得|高级程序员|程序设计|2020年1月1日|2020年1月31日|4,583英镑|
| 杰克|初级程序员|程序设计|2020年2月1日|2020年6月30日|2,083英镑|
| 理查德德|资深艺术家|艺术|2020年3月1日|2020年4月30日|3,750英镑|
| 罗德尼|QA负责人|质量保证部|2020年3月1日|2020年6月30日|4,333英镑|
| 项目1 -聘用1|高级制片人|生产部|2020年2月1日|2020年5月30日|3,458英镑|
| 罗杰|质量保证部|质量保证部|2020年1月1日|2020年4月30日|1,667英镑|
| 韦斯利|中级程控仪|程序设计|2020年2月1日|2020年5月31日|3,750英镑|
| 拉结|资深艺术家|艺术|2020年1月1日|2020年6月30日|3,333英镑|
| 项目1 -聘用2|首席程序员|程序设计|2020年1月1日|2020年7月31日|4,417英镑|
EmployeeSalaryTbl中的数据为:
| 员工|薪资起始日期|薪资终止日期|薪资|月薪|每日薪金|
| - -|- -|- -|- -|- -|- -|
| 鲍勃|2020年1月1日|2021年3月31日|5.2万英镑|4,333英镑|199英镑|
| 鲍勃|2021年4月1日|2022年3月31日|5万5千英镑|4,583英镑|211英镑|
| 鲍勃|2022年4月1日|九九年十二月三十一日|5万8千英镑|4,833英镑|222英镑|
| 戴夫|2020年1月1日|2021年3月31日|3.8万英镑|3,167英镑|146英镑|
| 戴夫|2021年4月1日|九九年十二月三十一日|4.2万英镑|3,500英镑|161英镑|
| 韦斯利|2020年1月1日|九九年十二月三十一日|4.5万英镑|3,750英镑|173英镑|
| 杰克|2020年1月1日|九九年十二月三十一日|2.5万英镑|2,083英镑|96英镑|
| 理查德德|2020年1月1日|九九年十二月三十一日|4.5万英镑|3,750英镑|173英镑|
| 罗德尼|2020年1月1日|九九年十二月三十一日|5.2万英镑|4,333英镑|199英镑|
| 项目1 -聘用1| 2020年1月1日|九九年十二月三十一日|4.15万英镑|3,458英镑|159英镑|
| 罗杰|2020年1月1日|九九年十二月三十一日|2万英镑|1,667英镑|77英镑|
| 史提|2020年1月1日|九九年十二月三十一日|2.7万英镑|2,250英镑|104英镑|
| 拉结|2020年1月1日|九九年十二月三十一日|4万英镑|3,333英镑|153英镑|
| 彼得|2020年1月1日|九九年十二月三十一日|3.4万英镑|2,833英镑|130英镑|
| 萨拉|2020年1月1日|九九年十二月三十一日|2.2万英镑|1,833英镑|84英镑|
| 克洛伊|2020年1月1日|九九年十二月三十一日|3.3万英镑|2,750英镑|127英镑|
| 马修|2020年1月1日|2021年3月31日|2.3万英镑|1,917英镑|88英镑|
| 马修|2021年4月1日|九九年十二月三十一日|2.8万英镑|2,333英镑|107英镑|
| 项目1 -聘用2| 2020年1月1日|九九年十二月三十一日|3.6万英镑|3,000英镑|138英镑|

oxcyiej7

oxcyiej71#

使用您输入的数据,并假设没有Excel版本限制(未在问题中指定),在单元格H2中输入以下公式:

=LET(namePrj, TB_Prj[Employee], startPrj, TB_Prj[Start Date], endPrj,
 TB_Prj[End Date],name, TB_Roster[Employee],start, TB_Roster[Salary Start Date],
 end, TB_Roster[Salary End Date],salary, TB_Roster[Salary Monthly],
 SOMs, H1:S1, EOMs, EOMONTH(SOM,0),
 BYCOL(SOMs, LAMBDA(SOM, LET(EOM, EOMONTH(SOM,0),
 namesActive, FILTER(namePrj, (startPrj <= SOM) * (endPrj >= EOM)),
  cost, FILTER(salary, (start <= SOM) * (IF(end > 0, end, EOM) >= EOM) *
    (ISNUMBER(XMATCH(name,namesActive))),0), sum(cost)
  )))
 )

两个 *Excel表 * 被定义为具有动态范围:项目信息TB_Prj,薪资信息TB_Roster,在H1中横向生成月份信息如下:

=EDATE(DATE(2020,1,1), SEQUENCE(1, 12, 0))

它会产生月份的第一天。在公式中表示为SOMs(月的开始)。类似地,我使用EOMs来表示每个相应的月的结束。
输出结果会产生1x12数组。
输出如下:

仅显示部分薪金表(TB_Roster

备注

请检查结果,您的数据需要清理,例如,薪金表中的Peter有两个日期间隔重叠的条目。
如果您无法使用表格(例如,输入基于SPILL公式,如FILTER),则可以使用范围。您可以定义以下两个数据集范围:prjSetrosterSet,然后定义每个Map的数据行,如下所示:INDEX(rng,,x),其中x表示每个范围中的相应列号,其中rngprjSetrosterSet。例如,name变量可以如下定义:

namePrj, INDEX(prjSet,,1)

说明

使用 *Excel表格 * 使其具有动态范围,因此在添加附加信息时不需要更改公式。我们使用LET函数使公式更易于维护,定义所需的输入和中间结果。
BYCOL用于迭代所有SOMs值。对于每个月初(SOM),我们执行以下操作:
从活动项目中查找namesActive,检查项目的开始时间是否早于或等于SOM,项目的结束时间是否大于或等于EOM。如果项目表中没有满足条件的名称,FILTER返回错误(#CALC!),因为Excel中不允许使用空数组。如果要处理这种情况,则需要调整公式(使用FILTERIF的第三个输入参数条件来计算cost)或更好地清理数据。我不会期望在一个给定的月份没有任何活动的项目在公司层面。
有了姓名列表后,我们转到第二个Excel表(TB_Roster),根据startend日期查找有效薪金。
我们在end中处理空值,假设如果没有值(数据被格式化为日期,所以空表示0)。下面的IF条件确保它(在第二个FILTER调用中):

(IF(end > 0, end, EOM) >= EOM)

所以如果end数组为正(日期表示为从0开始的正整数,即 * 整数 *),然后分配一个值,因此我们使用该值,否则(0)将替换为EOM。如果没有结束日期,则条件 * 始终为真 *(所有end值都考虑在内)。IF使用数组,它计算数组中每个元素的条件,并返回每个元素的相应值。通过这样做,我们将空值的情况固定为有效的情况,因此 * 不需要使用虚构的日期 *。
XMATCH相关的条件可确保我们仅根据上一次FILTER调用中的名称(项目表中的有效名称,即namesActive)筛选name。此筛选器的结果(cost)满足所有条件,并返回所有匹配的月薪。
如果根据过滤条件没有匹配,我们返回0(但是可以使用其他值,例如NA())。为了做到这一点,我们使用FILTER函数的第三个输入参数。
最后,我们将所有符合条件的薪资加总。

附加:检查间隔一致性

根据问题的答案:我提供的Excel: #CALC! error (Nested Array) when using MAP functions for counting interval overlaps,它可以用来检查日期间隔是否不正确(结束日期在开始日期之前),或者薪资表的间隔是否重叠:

=LET(names, TB_Roster[Employee], namesUx, UNIQUE(names),
 dates, TB_Roster[Salary Start Date]:TB_Roster[Salary End Date],
 maxDate, DATE(3000,1,1),
  byRowResult, BYROW(namesUx, LAMBDA(name,
    LET(set, FILTER(dates, names=name),
      startDates, INDEX(set,,1), endDates, INDEX(set,,2),
      calc, MAP(startDates, endDates, LAMBDA(start,end,
        LET(endAdj, IF(end > 0, end, maxDate),
        endDatesAdj, IF(endDates > 0, endDates, maxDate),
        startAfterEnd, IF(start <= endAdj, 0, 1),
        overlaps, IF(startAfterEnd > 0, 0,
          SUMPRODUCT((startDates <= endAdj) * (endDatesAdj >= start))-1),
        startAfterEnd &","& overlaps))),
        totals, TEXTSPLIT(TEXTJOIN(";",,calc),",",";"), intervals,
          1*INDEX(totals,,1), laps, 1*INDEX(totals,,2),
        SUM(intervals) + SUM(laps)/2
      )
    )), FILTER(HSTACK(namesUx, byRowResult), byRowResult<>0,
          "NO Overlaps or Wrong Ranges defined")
)

输出将是输入数据:

相关问题