用于汇总数据未更新的脚本

问题描述 投票:12回答:8

我有一张时间表数据的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触发器;没有快乐。如果您转到脚本编辑器并点击“保存”,它会更新,但这没有用。我错过了什么吗?

google-apps-script google-sheets google-apps custom-function
8个回答
34
投票

你错过了挑剔的缓存 窃听器 特征。它以这种方式工作:

Google认为所有自定义函数仅直接依赖于其参数值来返回其结果(您可以选择依赖于其他静态数据)。

鉴于此先决条件,他们只能在参数更改时评估您的函数。例如

假设我们在单元格B1上有文本“10”,然后在其他一些单元格上输入=myFunction(B1)

将评估myFunction并检索其结果。然后,如果将单元格B1值更改为“35”,将按预期重新评估自定义,并正常检索新结果。现在,如果再次将单元格B1更改为原始“10”,则无法重新评估,将立即从缓存中检索原始结果。

因此,当您使用工作表名称作为参数来动态获取它并返回结果时,您将破坏缓存规则。

不幸的是,没有这个惊人的功能,你就无法拥有自定义功能因此,您必须将其更改为直接接收值,而不是表单名称,或者不使用自定义函数。例如,您可以在脚本上有一个参数,告诉摘要应该去哪里,并且只要总数发生变化,就会让onEdit更新它们。


1
投票

缓存问题的另一种解决方案。

在您的方法中有一个虚拟变量。通过

Filter(<the cell or cell range>,1=1)

作为该参数的值。

EG

=getValueScript("B1","B4:Z10", filter(B4:Z10,1=1))

不使用过滤器的输出。但是它向电子表格表明该公式对B4:Z10范围敏感。


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
}

1
投票

我在函数中使用虚拟变量,此变量引用电子表格中的单元格,然后在脚本中有一个Myfunction(),在该单元格中写入Math.Ramdon数字。此“MyFunction”处于触发服务(编辑/当前项目触发器)下,您可以选择不同的事件触发器,例如开启或时间驱动,您可以选择一个时间段,从1分钟到一个月


0
投票

您可以做的是在电子表格中的某个位置设置另一个单元格,每次添加新工作表时都会更新该单元格。确保它不会针对每个更改进行更新,但仅限于您要进行计算时(在您添加工作表的情况下)。然后,将对此单元格的引用传递给自定义函数。如上所述,自定义函数可以忽略此参数。


0
投票

鉴于Henrique Abreu解释的功能,您可以尝试开箱即用的电子表格函数QUERY,SQL喜欢的查询是我在处理原始数据时经常使用的,并将数据作为汇总获取到不同的选项卡,结果数据更新在原始数据发生变化后实时进行。

我的建议是基于以下事实:您的脚本没有高级工作,例如URL提取,只是数据工作,因为没有实际数据读取,我无法使用QUERY提供精确的解决方案。

关于Henrique Abreu提到的缓存功能(我没有足够的声誉在他的回答下直接评论),我做了测试并发现:

  1. 看起来没有缓存工作,测试函数的脚本如下所示: function adder(base){Utilities.sleep(5000);返回基数+10; }

通过调用单元格在工作表中应用该自定义函数adder(),然后每次看到加载消息和总时间超过5秒时,前后更改该单元格值。它可能与此GAS issue:中提到的更新有关

这个问题现在已得到修复。 New Sheets中的自定义函数现在可以识别上下文,并且不会积极地缓存值。

  1. 本主题中提到的问题仍然存在,我的测试表明,Google表格每次都会重新计算自定义功能 由函数直接调用的值被更改。 function getCellValue(sheetName,row,col){var ss = SpreadsheetApp.getActiveSpreadsheet(); var sh = ss.getSheetByName(sheetName); return sh.getRange(row,col).getValue(); } enter image description here 黄色单元格中任何值的更改都将导致重新计算自定义函数;功能忽略实际数据源值的变化。 包含单元格位置的函数在工作表中更改。恩。在上方或左侧插入/删除行/列。

0
投票

我不想要一个虚拟参数。 YMMV对此。

1一个“项目列表”的单元格,一个是“刷新”

2如果单元格为“刷新”,则使用'onEdit'编写脚本:

a)清空文档缓存

b)用外部数据填充doc缓存(在我的例子中是一个表)

c)对于我的'getStockoData(...'自定义函数)的所有单元格

  • 得到公式
  • 设置'= 0'
  • 设定公式

d)将(1)中的单元格设置为“Ready”

这确实刷新了你想要的位但不快。


0
投票

由于google app脚本是JS的扩展,因此函数应该能够处理比函数签名中定义的更多args或更少的args。所以,如果你有一些功能

function ADD(a, b) {
  return CONSTANTS!$A$1 + a + b
}

然后你会把这个函数称为

=ADD(A1, B1, $A$2)

其中$ A $ 2是一些复选框(插入 - >复选框),您可以在需要更改工作表和单元格中的值后单击“刷新”CONSTANTS $ A $ 1


-1
投票

正如@Brionius所说,对该功能提出了额外的动态论证。如果你使用now()你可能有超时问题使更新有点慢...

cell A1 = int(now()*1000)
cell A2 = function(args..., A1)
© www.soinside.com 2019 - 2024. All rights reserved.