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

Excel formula apply conditions to all sheets same whole column

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

TL;DR;

我想在 sheet N 处应用一个 excel 公式,它将完整地考虑所有其他 sheet 中的所有相应列,而应用一些对所有列都相同的条件。

详情:

My spreadsheet 是一个非常简单和基本的费用会计,它有许多 sheet 按年份和日期命名的 2015.042015.052015.06等 第一行始终是标题(时间、日期、金额、项目、类别等),列始终是对应的(例如,在所有 sheet 中,列 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 - 如何将此公式应用于所有 sheets,即使稍后添加/删除了一些,例如相当于 "sheet wildcard "

 =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

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

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

P.S>。如果这很重要,请使用 OpenOffice Calc,但也尝试了 excel 中的所有内容,并更改了语法和不同的错误代码。

编辑 I - 解决方案

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

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

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

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

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

像这样:

{=SUMIF((INDIRECT("start"&".H"&ROW(A:A0)));$J16;INDIRECT("END"&".D"&ROW(A:A0)))}

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

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

试试这段代码:

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

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

如果您确实需要定义这些列范围(如 H2:H67),而不是仅仅查看整个列,您需要指定您将使用什么标准来做出决定,然后才能确定被编码到这个宏中。你确实说了"whole column",这肯定会看整个专栏。

我会尝试回答您的问题。

  1. Sheet 通配符

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

  1. 引用整列and/or整行

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

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

  1. 错误代码的含义

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

那么我会怎么做:

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

如您所见,K2 中的公式是

=SUMIF($H:$H48576,$J2,$D:$D48576)

J2中的公式为

=$'Sheet N'.$C

这是对 "Sheet N" 单元格 C20 的引用。

Sheet N 看起来像:

D20中的公式为

=SUM(Begin.K2:End.K2)

这是 3D 参考。从 sheet "Begin" 到 sheet "End" 的所有 sheet 中的所有单元格 K2 将被求和。

sheets "Begin" 和 "End" 只是空 sheets.

现在您可以随意复制 sheet“2015.01”,并将副本放在 sheet 和 "Begin" 和 "End" 之间。您可以根据新的月份更改复制的 sheet 的内容。只要在所有副本中 J2 是对 =$'Sheet N'.$C20 的引用并且在 K2 中是 SUMIF 公式,那么 D20 在 "Sheet N" 中将是"Sheet N".

中依赖于 C20 的所有 SUMIF 的总和

但最后要提到你:

I also know I can write a VBA macro, but at this point, it would take me much less effort and time to take some PHP excel library write some PHP lines , dump all in SQL and do it right.

您对 SQL 的提示是正确的。但同样在 SQL 中,您不会每个月都有自己的 table,然后从所有这些 table 中获取 UNION。您可以将所有费用核算在一个 table 中,并将月份作为一个字段。如果在 Spreadsheet 中也是如此,那么 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.

的值,则对 sheet 的第 4 列求和,其中名称匹配“2015.0[1,4]”