Google 用于在大型列表中查找和更新数据的表格脚本非常慢

Google Sheets script to find & update data on a large list is very slow

希望有人可以让我走上正确的道路。 (我认为这归结为我不了解如何使用客户端数组?)。

我拼凑的脚本在客户列表中查找匹配的名称,然后根据我在另一个选项卡上输入的数据更新一堆列。最后,我希望能够完全从另一个 sheet 执行此操作,但现在循环整个列表需要 3-4 分钟。我怀疑我需要做的是获取整个数据集,对其进行修改,然后设置新值,但我不确定我是否正确理解了问题。

function UpdateEntry() {
    var client_name=SpreadsheetApp.getActive().getSheetByName("Rolodex!C2").getValue()
    var addr=SpreadsheetApp.getActive().getSheetByName("Rolodex!C4").getValue()
    var client_phone=SpreadsheetApp.getActive().getRange("Rolodex!E4").getValue()
    var client_fax=SpreadsheetApp.getActive().getRange("Rolodex!E6").getValue()
    var client_WWW=SpreadsheetApp.getActive().getRange("Rolodex!E7").getValue()
      
    var data=SpreadsheetApp.getActive().getSheetByName("Rolodex").getRange("C4").getValue()
    var key=SpreadsheetApp.getActive().getSheetByName("Rolodex").getRange("C2").getValue()

    var database=SpreadsheetApp.getActive().getSheetByName("Database")
    var datalength=database.getDataRange().getValues().length
  
    database.getDataRange().getValues()
  
    for (var i = 1;[i]<=datalength ; i++){
        Logger.log('i: ' + i)
        if(database.getRange([i],[1]).getValue() == client_name){
            database.getRange([i],2).setValue(addr)
            database.getRange([i],3).setValue(client_phone)
            database.getRange([i],4).setValue(client_fax)
            database.getRange([i],5).setValue(client_WWW)
        }
    }
}

我相信你的现状和目标如下。

  • 您的脚本运行良好。但是工艺成本高
  • 您想降低脚本的处理成本。

修改点:

  • getValue()是ClassRange的方法。但在var client_name=SpreadsheetApp.getActive().getSheetByName("Rolodex!C2").getValue()处,getValue被用作ClassSheet的方法。在这种情况下,我认为错误发生在脚本的第一行。
    • 根据你的问题,我认为 getSheetByName 可能是 getRange
  • SpreadsheetApp.getActive()声明一次即可使用
  • client_name,addr,client_phone,client_fax,client_WWW 的值可以由一个 getValues 检索。
  • datakey 未使用。
  • database.getDataRange().getValues() 行未使用。
  • getValuesetValue在循环中使用。
    • 在这种情况下,首先使用 getValues 从 sheet 中检索值。然后,创建要放入 sheet 的值,然后使用 setValues.
    • 将创建的值放入 sheet
    • 这里作为重点,当使用setValues时,要求所有列的长度相同。请注意这一点。

当以上几点反映到你的脚本中,就会变成下面这样。

修改后的脚本:

function UpdateEntry() {
  var ss = SpreadsheetApp.getActive();

  // 1. Retrieve values of client_name, addr, client_phone, client_fax, client_WWW from Rolodex sheet.
  var sheet = ss.getSheetByName("Rolodex");
  var [[client_name],,[addr,,client_phone],,[,,client_fax],[,,client_WWW]] = ss.getRange("Rolodex!C2:E7").getValues();
  var ar = [client_name, addr, client_phone, client_fax, client_WWW];
  var arLength = ar.length;

  // 2. Retrieve values from database sheet.
  var database = ss.getSheetByName("Database");
  var values = database.getDataRange().getValues();
  var columnLength = values[0].length;

  // 3. Create values for putting to Database sheet using the values retrieved from Rolodex sheet.
  var res;
  if (columnLength > arLength) {
    res = values.map(r => r[0] == client_name ? ar.concat(r.slice(arLength)) : r);
  } else {
    res = values.map(r => r[0] == client_name ? ar : r.concat(Array(arLength - columnLength).fill("")));
  }
  
  // 4. Put the values to Database sheet.
  database.getRange(1, 1, res.length, res[0].length).setValues(res);
}

注:

  • 当您使用此修改后的脚本时,请在脚本编辑器中启用 V8 运行时。

  • 如果上面修改的脚本不是您期望的结果,您当前的脚本可能不是您期望的结果。如果我的理解是正确的,你能提供你期望的样本输入和输出吗?借此,我想确认一下。

参考文献: