Google apps script 在不中断公式的情况下更新命名范围

Google apps script 在不中断公式的情况下更新命名范围,google-apps-script,google-sheets,Google Apps Script,Google Sheets,我有一个电子表格,其中有许多引用命名范围的公式 电子表格在自定义菜单中有一个与之关联的脚本,该脚本可导入更新的数据,从而增加每个范围所需数据的长度。导入数据后,脚本将命名范围更新为新数据的长度 以下是导入新数据然后更新命名范围的代码块: // add the CSV menu. Might change this to be an automatic update base don date function onOpen() { var ss = SpreadsheetApp.getActi

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

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

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

// 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

阅读一些文档有一个句子

删除命名区域时,引用此命名区域的所有公式 射程将不再有效。但是,引用 命名范围将替换单元格值的命名范围 并继续工作

我不太清楚那是什么意思。如果我改为使用受保护的范围,它会全部工作吗?我试过编辑上面的代码?我阅读了有关getProtections的内容,因此尝试进行了一次小编辑:

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

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


这里有解决办法吗?如何使用脚本更新命名范围,而不破坏引用这些范围的现有公式?使用getProtections会带来一个解决方案还是仅仅是一种转移?

您提到的关于受保护范围的细节对您没有帮助。在其详细信息窗格中引用受保护范围定义的。您可以将受保护范围定义为命名范围,如果删除了命名范围,则不会破坏受保护范围定义。我也在一段时间之前遇到过这个问题,并认为这是其命名范围API中的一个严重错误。荒谬的是,他们的api没有办法修改它们,而不是删除和重新创建。我的意思是,如果我们使用命名范围,显然是因为我们希望它们会改变。很抱歉,这是一个非常老的问题,仍然没有解决。 编辑:参见 我从1.5年前就7岁了 和 我4岁,刚刚加了5岁
请两者都加星号。

您提到的有关受保护范围的详细信息对您没有帮助。在其详细信息窗格中引用受保护范围定义的。您可以将受保护范围定义为命名范围,如果删除了命名范围,则不会破坏受保护范围定义。我也在一段时间之前遇到过这个问题,并认为这是其命名范围API中的一个严重错误。荒谬的是,他们的api没有办法修改它们,而不是删除和重新创建。我的意思是,如果我们使用命名范围,显然是因为我们希望它们会改变。很抱歉,这是一个非常老的问题,仍然没有解决。 编辑:参见 我从1.5年前就7岁了 和 我4岁,刚刚加了5岁
请两者都加星号。

在公式中使用间接rangeName,而不仅仅是rangeName。以编程方式扩展范围的唯一方法是删除它,然后使用新定义将其添加回。此过程将中断公式并返回ref而不是范围名称

=sum(indirect("test1"),indirect("test3"))
这是一个混乱的、不必要的解决方法。如果您同意,请在问题跟踪器中标记该项目。

在公式中使用间接rangeName,而不仅仅是rangeName。以编程方式扩展范围的唯一方法是删除它,然后使用新定义将其添加回。此过程将中断公式并返回ref而不是范围名称

=sum(indirect("test1"),indirect("test3"))
这是一个混乱的、不必要的解决方法。如果您同意,请在问题跟踪器中标记该项目。

引用NamedRange的公式被该行打断

ss.Removenamedrangeopened[i]

我相信你可以省略这一行,直接转到

ss.setNamedRange开放[i],s.getRangerfr,rfc,rnr,rnc

这种方法似乎在GAS脚本中对我有效,该脚本在googlesheets的NamedRange中添加了一列。其他单元格中的公式引用此命名范围,并且在执行脚本时不会中断


我阅读了三篇“问题追踪者”的帖子,我了解到关注点是在命名范围集中生成重复条目。到目前为止,我还没有看到这种行为,所以这个错误可能已经被修复。

引用NamedRange的公式正在被这条线打断

ss.Removenamedrangeopened[i]

我相信你可以省略这一行,直接转到

ss.setNamedRange开放[i],s.getRangerfr,rfc,rnr,rnc

这种方法似乎在GAS脚本中对我有效,该脚本在googlesheets的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方法,而不是遍历命名范围的数组

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

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方法,而不是遍历命名范围的数组

谢谢你的信息。所以目前没有办法使用受保护的范围来实现这一点?我解释对了吗?在前面的一个问题中,我被告知使用间接的“namedRangeNameHere”来代替对命名范围的每个引用,这似乎起到了作用,但它并不像可能的那样优雅。我同意这是非常混乱的,并且在问题跟踪程序中产生了以下问题。我联系的其他世卫组织问题也提到了这一点。也许可以在你的新手机上发表评论。我认为最好有你的新版本,这样问题就不会在X other 2的评论中消失。谢谢你提供的信息。所以目前没有办法使用受保护的范围来实现这一点?我解释对了吗?在前面的一个问题中,我被告知使用间接的“namedRangeNameHere”来代替对命名范围的每个引用,这似乎起到了作用,但它并不像可能的那样优雅。我同意这是非常混乱的,并且在问题跟踪程序中产生了以下问题。我联系的其他世卫组织问题也提到了这一点。也许可以在你的新手机上发表评论。我认为最好有一个新的,这样这个问题就不会在另外两个的评论中消失。