根据唯一 ID Google 工作表更新或创建新行

Update or create new row based on Unique ID Google Sheets

我找到了一些与我想要做的很接近的选项,但没有完全匹配的选项。


请求很简单。

"Sheet A" - 硕士 Sheet(有 1 header 行)

"Sheet B" - 输入 Sheet(有 1 header 行)

“C 列”- 唯一 ID(两个 sheet 上的同一列)


触发器

操作数

重复操作,直到从第 2 行开始 Sheet B 中没有填充行(即排除第 1 行 header)。

谢谢

编辑

  1. 澄清我为什么要这样做。我有一个正在提交的表单,并将数据发送到 Google Sheets(Cognito -> Zapier -> Google Sheets)。此表单的一部分涉及重复部分(行项目)。当前导入响应的方法在正确添加新响应方面没有问题,但是在更新响应时,它无法 find/update 正确地为重复部分添加现有行。所以我就打算用SheetA当我的mastersheet,然后用SheetB简单的当一个receivingsheet。这样我就可以将每个条目(包括更新的条目)作为 Sheet B 上的“新”条目提交,然后让我的脚本进行更新。
  2. Sheet 每次提交或更新新的表单条目时,B 都会自动编辑。 “编辑”基本上是添加一个新行并将数据填充到该行中。向触发器添加一个 1 分钟的计时器可能是个好主意,这样如果要添加大量数据,它就会有时间发生。
  3. 我离脚本专家还差得很远。我只是浏览其他人制作的不同脚本,并尝试将它们组合起来,让它们为我所需要的工作。我发现脚本会移动一行然后将其删除,但它不会检查要更新的匹配值。我找到了其他检查唯一值并复制的脚本,但它们不会删除另一个 sheet 上的原始行。我试图将它们结合起来,但由于我没有基础知识,我似乎无法让它发挥作用。

作为解决方法,我会使用 onEdit 简单触发器和 O(n) 搜索

这是我的方法:

function onEdit(e) {
  // If it's not the Sheet B it won't make changes
  if (e.range.getSheet().getName() !== "Sheet B") {
    return;
  }

  var range = e.range;
  var numberRow = range.getA1Notation().slice(1);
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheetA = ss.getSheetByName("Sheet A");
  var sheetB = ss.getSheetByName("Sheet B");

  var currentRowB = sheetB.getRange(`A${numberRow}:D${numberRow}`);
  var id = currentRowB.getValues()[0][2];
  // There's to be 4 values in the row (no empty values)
  if(currentRowB.getValues()[0].filter(value => value !== '').length === 4) {

    // Get all the values in Sheet A
    var rows = sheetA.getDataRange().getValues();
    for (row=1; row < rows.length; row++) {
      // If column C matches the ID replace the row
      if(rows[row][2] === id) {
        var currentRowA = sheetA.getRange(`A${row+1}:D${row+1}`);
        currentRowA.setValues(currentRowB.getValues());
        currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
        return;
      }
    }

    // If the ID doesn't match then insert a new row
    var newRow = sheetA.getRange(`A${rows.length+1}:D${rows.length+1}`);
    newRow.setValues(currentRowB.getValues());
    currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
  }
}

符合您要求的:

  • 脚本从 C 列的 Sheet B 中找到唯一 ID,并在 C 列的 Sheet A 中查找它。(第 19-28 行)
  • 如果找到它,Sheet A 上的整个相应行将替换为 Sheet B 中的整个相应行。(第 22-24 行)
  • 如果找不到,则在 Sheet A 的底部添加一个新行,并将 Sheet B 中的整个相应行作为新记录添加到新行中Sheet A 的底部 (第 31-33 行)
  • Sheet B 上的整个相应行已删除。 (第 22 和 33 行)

我以这种 Sheet 格式为例:

两个 Sheet 具有相同的格式。请记住,此脚本会在替换之前检查是否存在有效行(在本例中为 4 列组成一行)。

作为一种不同的方法(处理空白数据)

总而言之,此脚本应该 运行 每 X 分钟或您想要的时间是否有新数据传入并不重要,因为此代码将在特定时间内处理所有数据。

我编辑了代码,以便将 Z1 单元格用作阻止单元格和基于时间的触发器:

触发器:

代码

function processCells() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheetA = ss.getSheetByName("Sheet A");
  var sheetB = ss.getSheetByName("Sheet B");

  // If it's not the Sheet B or if there's a process running it won't make changes
  if (sheetB.getName() !== "Sheet B" || sheetB.getRange("Z1") === "Running") {
    return;
  }

  // Use the Z1 cell in order to block or unblock this sheet
  sheetB.getRange("Z1").setValue('Running');

  // Process all the rows
  var numCells = sheetB.getDataRange().getValues().length + 1;
  for (numberRow = 2; numberRow <= numCells; numberRow++) {

    var currentRowB = sheetB.getRange(`A${numberRow}:D${numberRow}`);
    var id = currentRowB.getValues()[0][2];

    // Get all the values in Sheet A
    var rows = sheetA.getDataRange().getValues();
    var match = false;
    for (row=1; row < rows.length; row++) {
      // If column C matches the ID replace the row
      if(rows[row][2] === id) {
        var currentRowA = sheetA.getRange(`A${row+1}:D${row+1}`);
        currentRowA.setValues(currentRowB.getValues());
        currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
        match = true;
        break;
      }
    }

    if(!match) {
      // If the ID doesn't match then insert a new row
      var newRow = sheetA.getRange(`A${rows.length+1}:D${rows.length+1}`);
      newRow.setValues(currentRowB.getValues());
      currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
    }
  }

  sheetB.getRange("Z1").setValue('');
}

请注意,每次脚本 运行 都会检查是否有另一个脚本使用 Z1 处理这些行。

参考资料