Excel 公式将条件应用于所有工作表相同的整列

Posted

技术标签:

【中文标题】Excel 公式将条件应用于所有工作表相同的整列【英文标题】:Excel formula apply conditions to all sheets same whole column 【发布时间】:2015-10-01 08:03:18 【问题描述】:

这个问题可以看作是几个小问题,但主要目的是唯一的。

TL;DR;

我想在工作表 N 上应用一个 excel 公式,该公式将考虑所有其他工作表中的所有相应列,同时对所有列应用一些相同的条件。

详情:

我的电子表格是一个非常简单和基本的费用会计,其中有许多按年份和日期命名的表格 2015.042015.052015.06 等。 第一行始终是标题(时间、日期、金额、项目、类别等)并且列始终是对应的(例如,在所有工作表中,列 H 将是类别,D 将是金额)

起始公式为:

    =SUMIF('2015.07'.H2:H67;C20;'2015.07'.D2:D67)
// C20 is only a search condition like "travel", or "F&B"

它可以在这种简化的手动模式下工作,但是由于我们有电脑,而且我有一个程序员 M.O,我想稍微自动化一下,因此我的问题是:

1 - 如何将此公式应用于所有工作表,即使后来添加/删除了一些工作表,例如相当于“工作表通配符”

 =SUMIF('*'.H2:H67;C20;'*'.D2:D67) // all sheets

=SUMIF('2015*'.H2:H67;C20;'2015*'.D2:D67) // all year

2 - 由于列的长度不同,应用手动范围似乎很愚蠢,所以我尝试了

  =SUMIF('2015.07'.H:H;C20;'2015.07'.D:D) 

但它给了我几个不同的错误。

3 - 我能理解的错误之一,那就是第一行 TITLE 不是数字,所以我尝试了

=SUMIF('2015.07'.H1:H67;C20;ISNUMBER('2015.07'.D1:D99) )// err 504

也试过了

=SUMIF('2015.07'.H1:H67;C20;IF(ISNUMBER('2015.07'.D1:D99) ))// err 509

=SUMIF('2015.07'.H1:H67;C20;sum(IF(ISNUMBER('2015.07'.D1:D99)) ))// err 508

现在,我知道我可以采用简单的工作起始公式,将其放在每一页中,选择不带标题的确切范围,然后在最后一个摘要页面引用所有其他的 - 但说真的,我也可以使用ABACUS,这不是为什么发明像 excel 这样的工具的原因。还是我认为这个工具太多了?就这么原始吗?我不知何故拒绝相信它,只是责备自己没有像我应该知道的那样了解它。

我也知道我可以编写一个VBA 宏,但是在这一点上,我将花费更少的精力和时间来花费some php excel 库编写一些PHP 行,将所有内容转储到SQL 中并正确执行。但又一次 - 是我的错(可能)还是 excel 的错??

附注>。如果这很重要,请使用 OpenOffice Calc,但也尝试在 excel 中更改语法和不同的错误代码。

编辑我 - 解决方案

查看@Axel Richards 的答案后,即使它不能完全帮助我解决问题,但它确实帮助我找到了方法。

首先,我发现我遇到的错误是由于工作表本身的命名造成的。 显然,像2005.07(点)这样的名称将给出err 501,而2005-07(连字符)将给出err 502。这让我明白我之前的一些尝试实际上是正确的——但是命名方案造成了错误。

所以对我有用的最终公式是 . 请注意,这是一个数组公式,因此需要输入 CTRL+SHIFT+ENTER 而不仅仅是 ENTER ,它会产生大括号(我之前不知道..)

=SUMIF((INDIRECT("20150"&COLUMN(C$1:I$1)&".H"&ROW(A$1:A$500)));$J16;INDIRECT("20150"&COLUMN(C$1:I$1)&".D"&ROW(A$1:A$500)))

没有通配符的事实只对了一半,因为解决方案是定义一个开始时间段和结束时间段,公式将计算中间的所有工作表。就我的目的而言,这是某种通配符。

像这样:

=SUMIF((INDIRECT("start"&".H"&ROW(A$1:A$500)));$J16;INDIRECT("END"&".D"&ROW(A$1:A$500)))

COLUMN(C$1:I$1) 的使用实际上是创建一个数组 (3-9),ROW(A$1:A$500) 告诉你公式要考虑 500 行的所有内容。

这不是一个灵活或优雅的解决方案,但它确实有效。

【问题讨论】:

一种方法是编写一个小宏来检查工作簿中的所有可用工作表,然后更新公式以包含所有工作表。因此,如果有人稍后添加新工作表,宏将检测到它,并在手动运行或加载工作簿时更新公式 @Ahmad 好的,但是公式本身呢?如何选择一整列并验证条件(例如 ISNUMBER 和 C20) @Jerry - 即使在问题中复制的范围是错误的(应该是D2:D67 - 谢谢现在更正)它仍然应该工作,条件用人类语言说sum from D2 to D67 only if you find the string C20 inside H2 to H67所以如果范围是D2:D6 它应该只对那个范围求和(不管我的计算是否错误:-)?另外-这就是问题的重点-如何将其应用于整列,而不管其长度如何.. 好的,既然这个问题已经解决了,我首先要说的是(据我所知)没有可以为您提供文件中工作表列表的函数,也没有可以适应的函数添加/删除工作表。第二个问题可以通过使用SUMPRODUCT获取条件来解决。您的公式将变为 =SUMPRODUCT(('2015.07'.H1:H67=C20)*IF(ISNUMBER('2015.07'.D1:D97),'2015.07'.D1:D97,0)) @Jerry,感谢您抽出宝贵时间解决这个问题。以上仍然给我错误,即使它不会t - it does not resolve the D:D` 与Dx:Dn 问题。如果是这样的话,我想我只需要手动完成所有操作 【参考方案1】:

我会尝试回答你的问题。

    工作表通配符

这是不可能的。为什么?因为'2015.07'.H2:H67 中的工作表名称不仅仅是一个字符串,而是一个引用。如果您在“whatever”中将工作表名称从“2015.07”更改,那么所有引用此工作表的公式中的所有引用都将更改。

    引用整列和/或整行

这在 Openoffice (Libreoffice) 中是不可能的。在 Excel 中 =SUMIF('2015.07'!H:H,C20,'2015.07'!D:D) 将起作用。在 Openoffice 中,我们必须引用第一个单元格和最后一个单元格 =SUMIF($H$1:$H$1048576,C20,$D$1:$D$1048576)

顺便说一句:如果您在 Openoffice 中尝试 =SUMIF('2015.07'.H:H;C20;'2015.07'.D:D),错误应该是 #NAME?,因为 H 和 D 不是定义的名称。这与是否不是数字无关。 SUMIF 可以处理其总和范围内的非数字内容,但那里的错误值除外。

    错误代码的含义

https://help.libreoffice.org/Calc/Error_Codes_in_Calc

那么我会怎么做:

假设以下示例(在我的 Libreoffice 中是逗号公式参数分隔符):

正如你在K2 中看到的公式是

=SUMIF($H$1:$H$1048576,$J2,$D$1:$D$1048576)

J2中的公式是

=$'Sheet N'.$C$20

这是对“表 N”单元格 C20 的引用。

表格 N 看起来像:

D20 中的公式是

=SUM(Begin.K2:End.K2)

这是一个 3D 参考。从工作表“开始”到工作表“结束”的所有工作表中的所有单元格K2 将被求和。

“开始”和“结束”工作表只是空工作表。

现在您可以根据需要多次复制工作表“2015.01”,并将副本放置在工作表“开始”和“结束”之间。您可以根据新月份更改复制工作表的内容。只要在所有副本中是J2 引用=$'Sheet N'.$C20 并且在K2 中是SUMIF 公式,那么“表N”中的D20 将是所有那些SUMIFs 的总和,这将依赖于“Sheet N”中的C20

但最后还是要提一下:

我也知道我可以写一个 VBA 宏,但在这一点上,它需要 我花更少的精力和时间花一些 PHP excel 库写一些 PHP 行,全部转储到 SQL 中并正确执行。

您对 SQL 的提示是正确的。但同样在 SQL 中,您不会每个月都有自己的表,然后从所有这些表中获取UNION。您将在一张表中记录所有费用,并将月份作为字段。如果电子表格中也是如此,那么SUMIF 会很简单,不是吗?

关于宏观问题:

不能,因为 PHP 只能将一个很长的 =SUMIF...+SUMIF...+SUMIF... 公式放入单元格中。使用 VBA 或 Starbasic,您可以拥有 UDF(用户定义函数)。这更加灵活。

Openoffice Libreoffice 示例

Public Function SUMIFOS(sSheetName as String, lColSearch as Long, vSearchValue as Variant, lColSum as Long) as Variant

  oDoc = Thiscomponent
  sFormula = ""
  vResult = 0

  oTextSearch = CreateUnoService("com.sun.star.util.TextSearch")
  oOptions = CreateUnoStruct("com.sun.star.util.SearchOptions")
  oOptions.algorithmType = com.sun.star.util.SearchAlgorithms.REGEXP
  oOptions.searchString = sSheetName
  oTextSearch.setOptions(oOptions)

  For Each oSheet in oDoc.Sheets
   oFound = oTextSearch.searchForward(oSheet.Name, 0, Len(oSheet.Name)) 
   If  oFound.subRegExpressions <> 0 then

    sPath = ThisComponent.URL
    sSearchColumn = oSheet.Columns(lColSearch-1).AbsoluteName  
    sSumColumn = oSheet.Columns(lColSum-1).AbsoluteName  
    sSearchColumn = "'" & sPath & "'#" & sSearchColumn
    sSumColumn = "'" & sPath & "'#" & sSumColumn

    sFormula = "=SUMIF(" & sSearchColumn & ";""" & vSearchValue & """;" & sSumColumn & ")"

    oDocTMP = CreateUnoService("com.sun.star.sheet.SpreadsheetDocument")

    oSheetTMP = oDocTMP.createInstance("com.sun.star.sheet.Spreadsheet")
    oDocTMP.Sheets.insertByName("MySheet", oSheetTMP)
    oRangeTMP = oSheetTMP.getCellRangeByName("A1")
    oRangeTMP.Formula = sFormula    

    vResult = vResult + oRangeTMP.Value

    oDocTMP = Nothing
    oSheetTMP = Nothing
    oRangeTMP = Nothing

   End If
  Next  

  SUMIFOS = vResult

End Function

VBA 示例

Public Function SUMIFOS(sSheetName As String, lColSearch As Long, vSearchValue As Variant, lColSum As Long) As Variant

  Set oWB = ThisWorkbook

  vResult = 0

  Set oRegExp = CreateObject("vbscript.regexp")
  oRegExp.Pattern = sSheetName

  For Each oSheet In oWB.Sheets
   If oRegExp.test(oSheet.Name) Then
    Set rSearchColumn = oSheet.Columns(lColSearch)
    Set rSumColumn = oSheet.Columns(lColSum)

    vResult = vResult + WorksheetFunction.SumIf(rSearchColumn, vSearchValue, rSumColumn)

   End If
  Next

  SUMIFOS = vResult

End Function

用作公式:

=SUMIFOS("2015.0[1,4]",8,C20,4)

如果第 8 列包含 C20 的值,则对名称匹配“2015.0[1,4]”的工作表的第 4 列求和。

【讨论】:

我接受了您的回答,因为它为我指明了正确的方向。阅读我的编辑。 您的第一个数组公式有效。但如果工作表名称为2015.01 ... 2015.09,它也可以用作=SUMIF(INDIRECT("'2015.0"&amp;COLUMN($A$1:$I$1)&amp;"'.H"&amp;ROW($A$1:$A$500));$C20;INDIRECT("'2015.0"&amp;COLUMN($A$1:$I$1)&amp;"'.D"&amp;ROW($A$1:$A$500)))。请注意,我在引用中将工作表名称用单引号括起来。因此,您认为此类工作表名称将始终导致错误的假设是错误的。你也计算过这个数组公式得到结果所需的秒数吗?在我看来,这并不是一个真正的解决方案。 1- 好吧 - 我没有 presumed 这些名字会 always 产生错误。我只是说他们为我做了(使用我的设置/sw/os 版本)。2-我没有计算任何秒,因为它是分数。 (真正的工作已经在 20 分钟内用 PHP / mysql 完成。我只是借此机会学习了一些 Excel / Calc 函数,尽管你暗示这个问题只是针对bashing excel。)..TBC 4 - 我真的不明白你为什么指定它是not a solution。您可能会争辩说它是 slow solution ,或者不像我自己写的那样优雅 - 但它是满足我的需求的,也是原始问题中指定的。【参考方案2】:

试一下这段代码:

Sub CreateSumIfFormulaForAllSheets()
  Tmp = ""
  For i = 1 To Sheets.Count
    Tmp = Tmp & IIf(Tmp = "", "=SUMIF('" & Sheets(i).Name & "'!H:H,C20,D:D)", "+SUMIF('" & Sheets(i).Name & "'!H:H,C20,D:D)")
  Next i
Range("A1").Formula = Tmp
End Sub

假设您试图在所有工作表上 C20 位于所有工作表的 H 列中的所有工作表上的 D 列中的所有值的单一总和,这将起作用。只需将“A1”更改为您的公式通常所在的任何单元格。除非 D 列中有错误值,否则您不必担心 ISNUMBER,因为 SUMIF 会忽略文本。

如果您确实需要定义这些列范围(如 H2:H67),而不是只查看整个列,则需要指定在将其编码为宏。您确实说过“整列”,这肯定会查看整列。

【讨论】:

以上是关于Excel 公式将条件应用于所有工作表相同的整列的主要内容,如果未能解决你的问题,请参考以下文章

Excel中删除含有空值的整行或是整列

两个excel表,有一列内容相同,怎么把这两张表合并?

Excel用函数求同一行名字相同的数据最小值

如何将EXCEL中符合条件的数据利用公式复制到另一个工作表

Excel VBA怎么实现整行/列的遍历

请问,excel表格,在某行中查找某个数值对应的的列,再求此列的整列和。有啥办法。