【问题标题】:Replace entire sheet with another in Google Apps Scripts在 Google Apps 脚本中将整个工作表替换为另一个工作表
【发布时间】:2015-05-13 21:42:31
【问题描述】:

我想做的是电子表格中特定工作表中的仓库信息,并在每天结束时将其复制到第二个电子表格中。第二个电子表格将针对不需要全天运行的复制信息运行复杂的数据透视和报告。

我可以设置一个time-driven trigger,它将每天在一小时内运行该作业。

我正在编写以下脚本,它使用SpreadsheetApp.getActiveSpreadsheet 来获取当前的电子表格。然后使用spreadsheet.getSheetByName 获取要备份的单个工作表。然后使用sheet.copyTo 方法将当前工作表添加到新的电子表格中。我通过使用SpreadsheetApp.openById 查找 ID 来获取新的电子表格,如下所示:

function startBackupJob() {

  var currentSpreadSheet = SpreadsheetApp.getActiveSpreadsheet()
  var masterSheet = currentSpreadSheet.getSheetByName("Sheet1")

  var backupSpreadSheetId = "#######################################";
  var backupSpreadSheet = SpreadsheetApp.openById(backupSpreadSheetId);

  // var backupSheet = backupSpreadSheet.getSheetByName("Sheet1");
  // backupSpreadSheet.deleteSheet(backupSheet);

  masterSheet.copyTo(backupSpreadSheet).setName("Sheet1");

}

我遇到的问题是copyTo 将创建一个新的工作表,而不是覆盖现有的电子表格。移动到新工作簿的目的是从数据中运行数据透视表,而不是重新连接它们以指向新工作表。

我可以删除以前的工作表来为新工作表腾出空间,但这也会杀死数据透视表上的引用,因此没有多大帮助。

有没有一种简单的方法可以将一个工作表的全部内容转移到另一个工作表?


这类似于(但不同于)以下问题:


更新

我可以通过在每张纸上调用getRange 然后像这样使用getValuessetValues 来做到这一点:

var currentValues = masterSheet.getRange(1, 1, 50, 50).getValues()
backupSheet.getRange(1, 1, 50, 50).setValues(currentValues)

但我担心主工作表与备用工作表的可用范围不同的极端情况。我也不想在该范围内硬编码,而是让它包含整个工作表。如果我打电话给.getRange("A:E"),那么这两个工作表必须具有完全相同的行数,这不太可能。

【问题讨论】:

  • 我没有将数据复制到第二个电子表格文件中,而是有一个中间数据文件,第二个电子表格文件可以访问该文件。现在看来,您的第二张工作表不够动态,无法弄清楚如何引用传入的数据。我只是在这里做一个疯狂的猜测。似乎问题的一部分是第二张表能够设置对新数据的引用。如果出于任何原因需要,您可以逐个单元格地设置第二个工作表中的值。

标签: google-apps-script google-sheets


【解决方案1】:

您的更新已经完成了大约 90% 的路程。诀窍是在将数据复制到其中之前明确检查目标工作表的大小。例如,如果我做了这样的事情:

var cromulentDocument = SpreadsheetApp.getActiveSpreadsheet();
var masterSheet = cromulentDocument.getSheetByName('master');
var logSheet = cromulentDocument.getSheetByName('log');
var hugeData = masterSheet.getDataRange().getValues();
var rowsInHugeData = hugeData.length;
var colsInHugeData = hugeData[0].length;

/* cross fingers */
logSheet.getRange(1, 1, rowsInHugeData, colsInHugeData).setValues(hugeData);

...那么我的成功将完全取决于logSheet 是否至少与masterSheet 一样大。这很明显,但不太明显的是,如果logSheet 更大,那么边缘会留下一些旧垃圾。不好。

让我们试试别的。和以前一样,我们将获取主数据,但我们还将调整 logSheet 的大小。如果我们不关心 logSheet 太大,我们可能只需要 clear() 里面的数据,但让我们保持整洁。

var cromulentDocument = SpreadsheetApp.getActiveSpreadsheet();
var masterSheet = cromulentDocument.getSheetByName('master');
var logSheet = cromulentDocument.getSheetByName('log');
var hugeData = masterSheet.getDataRange().getValues();
var rowsInHugeData = hugeData.length;
var colsInHugeData = hugeData[0].length;

/* no finger crossing necessary */
var rowsInLogSheet = logSheet.getMaxRows();
var colsInLogSheet = logSheet.getMaxColumnss();

/* adjust logSheet length, but only if we need to... */
if (rowsInLogSheet < rowsInHugeData) {
  logSheet.insertRowsAfter(rowsInLogSheet, rowsInHugeData - rowsInLogSheet);
} else if (rowsInLogSheet > rowsInHugeData) {
  logSheet.deleteRows(rowsInHugeData, rowsInLogSheet - rowsInHugeData);
}

/* likewise, adjust width */
if (colsInLogSheet < colsInHugeData) {
  logSheet.insertColumnsAfter(colsInLogSheet, colsInHugeData - colsInLogSheet);
} else if (colsInLogSheet > colsInHugeData) {
  logSheet.deleteColumns(colsInHugeData, colsInLogSheet - colsInHugeData);
}

/* barring typos, insert data with confidence */
logSheet.getRange(1, 1, rowsInHugeData, colsInHugeData).setValues(hugeData);

这里发生的事情非常简单。我们计算出日志需要多大,然后调整目标工作表的大小以匹配该数据。

【讨论】:

  • 完美!附带问题:所有这些繁琐的操作是否对仅在备份表上使用 IMPORTRANGE 并传入主表的 ID 有任何好处。我主要是在尝试提高性能,因为有大量行,而且我怀疑在同一个文档中运行数据透视表会加剧这个问题。 Import Range 实时更新,这很好,但我担心它必须花费同样多的精力以这种方式推动更改。
  • 随着您的“主”数据变得越来越大,这种方法的好处越来越多,因为电子表格不会不断检查更新。我还看到IMPORTRANGE 的问题,其中目标区域只是显示为空白,直到您强制刷新带有IMPORTRANGE 的单元格。我还经常遇到使用IMPORTRANGEd 数据的公式(或数据透视表)根本看不到基础数据的问题,即使它显示在 UI 中也是如此。
猜你喜欢
  • 1970-01-01
  • 2021-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 2014-09-21
  • 2023-02-11
相关资源
最近更新 更多