我有一张时间表数据的Google电子表格;它每个月有一张工作表,每张工作表有很多六个列块,每个客户一个块。
我创建了一个摘要表,其中包含每个客户的总数并将其显示在列表中:
function getClientTotals(sheetname, colcount)
{
colcount = colcount ? colcount : 6;
var res;
var ss = SpreadsheetApp.openById('myid_goes_here');
if(ss)
{
res = [];
var totrow = ss.getRange(sheetname + '!A1:ZZ1').getValues()[0];
for(var i = 0; i < totrow.length; i += colcount)
{
res.push([totrow[i], totrow[i + colcount - 1]]);
}
}
return res;
}
然后我在我的摘要表中添加了一个单元格,其中包含=getClientTotals($C$7,$C$8)
,其中传递了月份的工作表名称和每个客户端的列数(如果是“架构”修改。
这一切都运行正常,但是,在更改源数据时它不会更新。我添加了onEdit
触发器;没有快乐。如果您转到脚本编辑器并点击“保存”,它会更新,但这没有用。我错过了什么吗?
答案 0 :(得分:33)
你错过了挑剔的缓存 bug 功能。它的工作原理如下:
Google认为您的所有自定义函数都直接依赖 参数值来返回结果(您可以选择依赖其他静态数据)。
鉴于此先决条件,他们只能在参数更改时评估您的功能。 e.g。
假设我们在单元格B1上有文本“10”,然后在其他一些单元格上输入=myFunction(B1)
将评估myFunction并检索其结果。然后,如果将单元格B1值更改为“35”,将按预期重新评估自定义,并正常检索新结果。 现在,如果再次将单元格B1更改为原始“10”,则无法重新评估,将立即从缓存中检索原始结果。
因此,当您使用工作表名称作为参数来动态获取它并返回结果时,您将破坏缓存规则。
不幸的是,没有这个惊人的功能,你就无法拥有自定义功能。因此,您必须将其更改为直接接收值,而不是表单名称,或者不使用自定义函数。例如,您可以在脚本上设置一个参数,告诉摘要应该去哪里,并在总计更改时让onEdit
更新它们。
答案 1 :(得分:1)
缓存问题的另一种解决方案。
在您的方法中有一个虚拟变量。 传递
Filter(<the cell or cell range>,1=1)
作为该参数的值。
e.g。
=getValueScript("B1","B4:Z10", filter(B4:Z10,1=1))
不使用过滤器的输出。但是它向电子表格表明该公式对B4:Z10范围敏感。
答案 2 :(得分:1)
我有一个类似的问题,为工作创建一个仪表板。 Chamil上面的解决方案(即使用Sheet的Filter函数作为函数传递给函数中的虚拟变量)工作得很好,尽管Arsen最近的评论。在我的情况下,我使用一个函数来监视一个范围,并且无法在相同的范围内使用过滤器,因为它创建了一个循环引用。所以我只有一个单元格(在我的情况下,在下面的代码中为E45),我在任何时候都希望我的函数更新时更改了数字:
=myFunction("E3:E43","D44",filter(E45,1=1))
正如Chamil指出的那样,脚本中没有使用过滤器:
function myFunction(range, colorRef, dummy) {
variable 'dummy' not used in code here
}
答案 3 :(得分:1)
我在函数中使用了虚拟变量,该变量引用电子表格中的单元格 那么y在脚本中有一个Myfunction(),可以在该单元格中写入Math.Ramdon数字。 此“ MyFunction”位于触发器服务(“编辑” /“当前项目”触发器)下,您可以选择不同的事件触发器,例如“打开”或“时间驱动”,在那里您可以选择例如从1分钟到一个月的时间段
答案 4 :(得分:0)
您可以做的是在电子表格中的某个位置设置另一个单元格,每次添加新工作表时都会更新该单元格。确保它不会针对每个更改进行更新,但仅限于您要进行计算时(在您添加工作表的情况下)。然后,将对此单元格的引用传递给自定义函数。如上所述,自定义函数可以忽略此参数。
答案 5 :(得分:0)
鉴于Henrique Abreu解释的功能,您可以尝试开箱即用的电子表格功能QUERY ,SQL喜欢的查询是我经常在工作中使用的 在原始数据上,并将数据作为摘要获取到不同的选项卡,结果数据在原始数据更改后实时更新。
我的建议是基于以下事实:您的脚本没有高级工作,例如URL提取,只是数据工作,因为没有实际数据读取,我无法使用QUERY提供精确的解决方案。
关于Henrique Abreu提到的缓存功能(我没有足够的声誉直接根据他的回答发表评论),我做了测试并发现:
看起来没有缓存工作,测试功能的脚本如下所示:
function adder(base){ 使用Utilities.sleep(5000); 返回基数+10; }
通过调用单元格在工作表中应用该自定义函数adder(),然后每次看到加载消息和总时间超过5秒时,前后更改该单元格值。 它可能与此GAS issue:
中提到的更新有关此问题现已修复。新表中的自定义函数现在可以识别上下文,并且不会积极地缓存值。
本主题中提到的问题仍然存在,我的测试表明,Google表格每次重新计算自定义功能
function getCellValue(sheetName,row,col) { var ss = SpreadsheetApp.getActiveSpreadsheet(); var sh = ss.getSheetByName(sheetName); return sh.getRange(row,col).getValue(); }
黄色单元格中任何值的更改都将导致重新计算自定义函数;函数忽略实际数据源值的变化。
答案 6 :(得分:0)
我不想有一个虚拟参数。 YMMV对此。
1作为&#39;项目列表的单元格,其中一个是&#34;刷新&#34;
如果单元格为&#34;刷新&#34;a)清空文档缓存
b)使用外部数据(在我的情况下为表格)填充文档缓存
c)对于我的&#39; getStockoData(...&#39;自定义函数
的所有单元格得到公式
设置&#39; = 0&#39;
设置fromula
d)将(1)中的单元格设置为&#34; Ready&#34;
这会刷新您想要的位但不快。
答案 7 :(得分:0)
由于google app脚本是JS的扩展,因此函数应该能够处理比函数签名中定义的参数更多或更少的args。因此,如果您有类似的功能
function ADD(a, b) {
return CONSTANTS!$A$1 + a + b
}
然后您将这个函数称为
=ADD(A1, B1, $A$2)
其中$ A $ 2是一些复选框(插入->复选框),在您需要从工作表和单元格中更改值CONSTANTS $ A $ 1
时,可以单击以“刷新”答案 8 :(得分:0)
使用google财务函数作为参数。像= GOOGLEFINANCE(“ CURRENCY:CADARS”)
这些功能每x分钟强制重新加载
答案 9 :(得分:-1)
正如@Brionius所说,对该功能提出了额外的动态论证。如果你使用now()你可能有超时问题使更新有点慢......
cell A1 = int(now()*1000)
cell A2 = function(args..., A1)