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

sam*_*sam 4 javascript google-sheets google-apps-script

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

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

  • Spreadsheet1在A:F中有数据,party1(一组用户)在其中写入数据.
  • Spreadsheet2是从电子表格1导入A:F的范围,然后在G:M中写入更多细节,数据由party2写入.

它的工作方式是party1在A1-F10行的数据中写入,然后party2根据party1写入的内容将其附加数据写入spreadsheet2.

例如,如果Spreadsheet1 A1:F10是项目的名称,价格,交货时间,数量等,Spreadsheet2 G1:M10可能是订单日期的一堆数据,交付(是/否)等.

我现在面临的问题是,当设置电子表格时,他们会在电子表格2中读取精细数据,即电子表格1中的1-10行,电子表格中为1-10,但过了一段时间,一些新行被添加到旧行之间的电子表格1中5.这会抛出电子表格2中的顺序(现在,电子表格1中的第4行与电子表格2中的第4行不对齐,并且数据变得格格不入).是否存在此问题,即使有人在现有行的中间添加了其他行,两个电子表格都会更新?

Mog*_*dad 5

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

我们可以根据您的情况调整这个想法,使用一个脚本来调整电子表格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  - - - - - >
Run Code Online (Sandbox Code Playgroud)

演示

这就是行动的样子!此示例在同一电子表格中使用两个工作表,仅为方便起见.在演示中,在工作表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);
}
Run Code Online (Sandbox Code Playgroud)