在不破坏公式的情况下更新命名范围

Update named ranges without breaking formula

我有一个电子表格,其中包含许多引用命名范围的公式。

电子表格在自定义菜单中有一个与之关联的脚本,该菜单导入更新的数据,这会增加每个范围内所需数据的长度。导入数据后,脚本会将命名范围更新为新数据的长度。

这是导入新数据然后更新命名范围的代码块:

// add the CSV menu. Might change this to be an automatic update base don date
function onOpen() {
 var ss = SpreadsheetApp.getActiveSpreadsheet();
  var csvMenuEntries = [{name: "Update Data", functionName: "importFromCSV"}];
  ss.addMenu("Update", csvMenuEntries);
}

function importFromCSV() {
      var file = DriveApp.getFilesByName("double_leads_data.csv");// get the file object
      var csvFile = file.next().getBlob().getDataAsString();// get string content
      var csvData = Utilities.parseCsv(csvFile);
      var ss = SpreadsheetApp.getActiveSpreadsheet();
      var sheet = ss.getSheetByName('DataImport'); // only add data to the tab DataImport to prevent overwriting other parts of the spreadsheet
      sheet.getRange(2,1, csvData.length, csvData[0].length).setValues(csvData);// write to sheet in one single step. Start at row 2 (getRange(2... )
      SpreadsheetApp.getUi().alert('Data Updated');

      //now update the named ranges if they have changed in length
       var openEnded = ["business_unit", "channel", "date", "leads", "medium", "region" ];

      for(i in openEnded) {
        var r = ss.getRangeByName(openEnded[i]);
        var rlr = r.getLastRow();
        var s = r.getSheet();
        var slr = s.getMaxRows();
        if(rlr==slr ) continue; // ok as is-skip to next name
        var rfr = r.getRow();
        var rfc = r.getColumn();
        var rnc = r.getNumColumns();
        var rnr = slr - rfr + 1;
        ss.removeNamedRange(openEnded[i]);
        ss.setNamedRange( openEnded[i], s.getRange(rfr, rfc, rnr, rnc ));
      }
}

一切正常 - 数据导入和命名范围更新。但是,在更新之后,所有引用命名范围的公式都会中断并显示 #REF 他们之前引用相应命名范围的位置。

阅读一些文档here有一句话

When you delete a named range, any formulas referencing this named range will no longer work. However, protected ranges that reference a named range will swap out the named range for the cell values themselves and continue to work.

我不太确定那是什么意思。如果我改用受保护的范围,它会起作用吗?我试过编辑上面的代码?我阅读了有关 getProtections() here 的信息,因此尝试进行了一些小修改:

var openEnded = ["businessunit2", "date2", "leads2", "medium2", "region2", "saleschannel2" ] ;

var openEnded = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE)

我真的没想到这会奏效,但值得一试。

这里有解决办法吗?如何在不破坏引用这些范围的现有公式的情况下使用脚本更新命名范围?使用 getProtections() 会带来解决方案还是只是转移注意力?

您提到的有关受保护 运行ges 的详细信息对您没有帮助。那指的是其详细信息窗格中受保护的 运行ge 定义。您可以将受保护的 运行ge 定义为命名的 运行ge,如果删除命名的 运行ge,它不会破坏受保护的 运行ge 定义。
我不久前也 运行 进入了这个,并认为这是他们命名的 运行ges api 中的一个严重错误。荒谬的是,他们的 api 没有办法修改它们(而不是删除和重新创建)。我的意思是,如果我们使用 named 运行ges 显然是因为我们希望它们发生变化。抱歉,运行t 但这是一个非常老的问题,仍然存在问题。
编辑:见
https://code.google.com/p/google-apps-script-issues/issues/detail?id=1040(我在 1.5 年前排名第 7)

https://code.google.com/p/gdata-java-client/issues/detail?id=196(我是#4,刚刚在那里添加了#5)
请为两者加注星标。

在公式中使用 INDIRECT("rangeName") 而不仅仅是 rangeName。以编程方式扩展范围的唯一方法是删除它,然后使用新定义将其添加回来。此过程打破了公式和 returns #ref 而不是范围名称。

=sum(indirect("test1"),indirect("test3"))

这很麻烦,应该是不必要的解决方法。如果您同意,请在问题跟踪器中为该项目加注星号。 https://code.google.com/p/google-apps-script-issues/issues/detail?id=5048

引用 NamedRange 的公式被行

打破

ss.removeNamedRange(openEnded[i]);

相信你可以省略这一行,直接进入

ss.setNamedRange( openEnded[i], s.getRange(rfr, rfc, rnr, rnc ));

这种方法似乎在 GAS 脚本中对我有用,该脚本将一列添加到 Google 工作表中的 NamedRange。其他单元格中的公式引用这个命名范围,并且在我的脚本执行时不会被破坏

我阅读了三个问题跟踪器帖子,我知道问题是在命名范围集中生成重复条目。到目前为止,我还没有看到这种行为,所以也许这个错误已经修复了。

以下代码将更新命名范围而不删除它,如果范围不存在则创建该范围。

function fixNamedRange (ss, name, range) {
  var ssNamedRanges = ss.getNamedRanges();
  var ssRangeNames = ssNamedRanges.map (function (ssRange) { 
      return ssRange.getName(); 
    }
  );
  var myRange = ssNamedRanges[ssRangeNames.indexOf(name)];

  if (myRange) {
    return myRange.setRange(range);
  } else {
    ss.setNamedRange(name, range);
    return -1;
  }
}

编辑为使用 .map 方法而不是遍历命名范围数组。