Excel 公式将条件应用于所有工作表相同的整列
Excel formula apply conditions to all sheets same whole column
这个问题可以看作是几个小问题,但主要目的是一个。
TL;DR;
我想在 sheet N 处应用一个 excel 公式,它将完整地考虑所有其他 sheet 中的所有相应列,而应用一些对所有列都相同的条件。
详情:
My spreadsheet 是一个非常简单和基本的费用会计,它有许多 sheet 按年份和日期命名的 2015.04
、2015.05
、2015.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",这肯定会看整个专栏。
我会尝试回答您的问题。
- Sheet 通配符
这是不可能的。为什么?因为 '2015.07'.H2:H67
中的 sheet 名称不仅仅是一个字符串,而是一个引用。如果您在 "whatever" 中将 sheet 名称从“2015.07”更改,那么所有引用此 sheet 的公式中的所有引用都将更改。
- 引用整列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
可以处理其总和范围内的非数字内容,但那里有错误值。
- 错误代码的含义
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]”
这个问题可以看作是几个小问题,但主要目的是一个。
TL;DR;
我想在 sheet N 处应用一个 excel 公式,它将完整地考虑所有其他 sheet 中的所有相应列,而应用一些对所有列都相同的条件。
详情:
My spreadsheet 是一个非常简单和基本的费用会计,它有许多 sheet 按年份和日期命名的 2015.04
、2015.05
、2015.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",这肯定会看整个专栏。
我会尝试回答您的问题。
- Sheet 通配符
这是不可能的。为什么?因为 '2015.07'.H2:H67
中的 sheet 名称不仅仅是一个字符串,而是一个引用。如果您在 "whatever" 中将 sheet 名称从“2015.07”更改,那么所有引用此 sheet 的公式中的所有引用都将更改。
- 引用整列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
可以处理其总和范围内的非数字内容,但那里有错误值。
- 错误代码的含义
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
.