同步独立的电子表格行,由 IMPORTRANGE() 填充

IT技术 javascript google-apps-script google-sheets
2021-03-17 04:55:01

我需要同步 2 个相互引用的电子表格的内容,如果在其中一个工作表中添加新行,则保持它们的行同步。

我在 Google 表格中有 2 个电子表格(尽管如果有跨电子表格解决方案,Excel 和 GS 都会很棒):

  • Spreadsheet1 在 A:F 中有数据,而 party1(一组用户)将他们的数据写入其中。
  • Spreadsheet2 是从spreadsheet1 中导入A:F 的范围,然后在G:M 中写入更多详细信息,数据由party2 写入。

它的工作方式是派对 1 在 A1-F10 行中写入他们的数据,然后派对 2 根据派对 1 写入的内容在电子表格 2 中写入他们的附加数据。

例如,如果 Spreadsheet1 A1:F10 是商品的名称、价格、预计交货时间、数量等,则 Spreadsheet2 G1:M10 可能是有关订单日期、交货(是/否)等的一堆数据。

我目前遇到的问题是,当设置电子表格时,它们可以很好地读取,即电子表格 1 中的 1-10 与电子表格 2 中的 1-10 对齐,但过了一会儿,一些新行被添加到电子表格 1 之间的旧行 2- 5. 这会抛出电子表格 2 中的顺序(现在电子表格 1 中的第 4 行与电子表格 2 中的第 4 行不对齐,数据变得不正常)。是否存在这样的情况,以便即使有人在现有行的中间添加额外的行,两个电子表格也会更新?

2个回答

这是数据库设计中的一个经典问题;如何关联两个表中的信息。通常的解决方案是使用关键数据两个表中都存在的一个或多个列并提供唯一标识符或键来关联行。

我们可以根据您的情况调整这个想法,使用一个脚本来调整电子表格 2 中行的位置以与电子表格 1 同步。为此,我们需要确定一个键 - 例如名称列 - 它必须存在于两个电子表格中.

这需要在电子表格 2 中进行小的更改,其中名称列现在将出现在 G 列中,紧跟在 AF 列中的导入范围之后。

    A      B             C            D       E         F        G         H           I           J
| Name | Price | est delivery time | qty | etc. of | an item | Name  | order date | delivered | blah blah |
 < - - - - - - - - - - - -  Imported  - - - - - - - - - - - >  *KEY*  < - - - - - -  sheet 2  - - - - - >

演示

这是实际操作的样子!这个例子在同一个电子表格中使用了两张工作表,只是为了方便。在演示中,在工作表 1 的中间添加了一个新的“项目”行,由于该=IMPORTRANGE()功能,该行会自动出现在工作表 2 上同步功能在 1 分钟定时触发器上运行,您会看到它在大约 20 秒内移动事物。

您可以在此处获取电子表格 + 嵌入脚本的副本

视频

代码

/**
 * Call syncTables() with the name of a key column.
 */
function doSyncTables() {
  syncTables( "Name" );
}

/*
 * Sync "Orders" spreadsheet with imported rows from "Items" spreadsheet.
 *
 * From: http://stackoverflow.com/a/33172975/1677912
 *
 * @param {String}  keyName    Column header used as key colum, appears
 *                             at start of "Orders" data, following
 *                             "Items" data.
 */
function syncTables( keyName ) {
  var sheet2 = SpreadsheetApp.openById( sheetId2 ).getSheetByName('Orders');

  // Get data
  var lastCol = sheet2.getLastColumn();
  var lastRow = sheet2.getLastRow();      // Includes all rows, even blank, because of =importRange()
  var headers = sheet2.getRange(1, 1, 1, lastCol).getValues()[0];
  var keyCol = headers.lastIndexOf( keyName ) + 1;
  var itemKeys = sheet2.getSheetValues(1, 1, lastRow, 1).map(function(row) {return row[0]});
  var itemData = sheet2.getSheetValues(1, 1, lastRow, keyCol-1);
  var orderData = sheet2.getSheetValues(1, keyCol, lastRow, lastCol-keyCol+1);

  var ordersByKey = [];  // To keep track of orders by key

  // Scan keys in orderData
  for (var row=1; row<orderData.length; row++) {
    // break loop if we've run out of data.
    var orderKey = orderData[row][0];
    if (orderKey === '') break;

    ordersByKey[ orderKey ] = orderData.slice(row, row+1)[0];

    var orderKey = orderData[row][0];
  }

  var newOrderData = [];  // To store reordered rows

  // Reconcile with Items, fill out array of matching orders
  for (row = 1; row<itemData.length; row++) {
    // break loop if we've run out of data.
    var itemKey = itemData[row][0];
    if (itemKey === '') break;

    // With each item row, match existing order data, or add new
    if (ordersByKey.hasOwnProperty(itemKey)) {
      // There is a matching order row for this item
      newOrderData.push(ordersByKey[itemKey]);
    }
    else {
      // This is a new item, create a new order row with same key
      var newRow = [itemKey];
      // Pad out all columns for the new row
      for (var col=1; col<orderData[0].length; col++) newRow.push('');
      newOrderData.push(newRow);
    }
  }

  // Update spreadsheet with reorganized order data
  sheet2.getRange(2, keyCol, newOrderData.length, newOrderData[0].length).setValues(newOrderData);
}
@ZigMandel 感谢您的澄清,我已经完全更新了答案。这已经足够了,我可能很快就会写博客!
2021-04-23 04:55:01
您知道是否有任何方法可以使脚本“在更改时”运行,而不是每分钟运行一次?
2021-05-05 04:55:01

mogsdad 目前的回答一如既往地出色。我只是想指出一个不太复杂的替代方案:

如果您可以忍受防止电子表格 1 允许插入或删除行,您将避免该问题。例如,您可以使用列标记“已删除”,而不是删除行(并使用过滤器从视图中删除)。

为了防止在电子表格 1 中插入和删除行,只需在右侧选择整个未使用的列,并创建一个受保护的范围,这样任何编辑者都没有权限。防止在行级别修改到最后一个现有行(但仍可以在范围下方插入新行)

它也不会阻止用户交换两行的数据。但了解这个更简单的替代方案仍然很好。