根据唯一 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 上的同一列)
触发器
- SheetB编辑
操作数
- 脚本从 C 列的 Sheet B 中找到唯一 ID,并在 C 列的 Sheet A 中查找它。
- 如果找到它,Sheet A 上的 整个相应行 被 替换为 Sheet B.
中的整个相应行
- 如果没有找到,将在 Sheet A 的底部添加一个新行,来自 Sheet B 的 的整个相应行是作为新记录添加到 Sheet A.
底部的新行中
- Sheet B 上的 整个行 已删除。
重复操作,直到从第 2 行开始 Sheet B 中没有填充行(即排除第 1 行 header)。
谢谢
编辑
- 澄清我为什么要这样做。我有一个正在提交的表单,并将数据发送到 Google Sheets(Cognito -> Zapier -> Google Sheets)。此表单的一部分涉及重复部分(行项目)。当前导入响应的方法在正确添加新响应方面没有问题,但是在更新响应时,它无法 find/update 正确地为重复部分添加现有行。所以我就打算用SheetA当我的mastersheet,然后用SheetB简单的当一个receivingsheet。这样我就可以将每个条目(包括更新的条目)作为 Sheet B 上的“新”条目提交,然后让我的脚本进行更新。
- Sheet 每次提交或更新新的表单条目时,B 都会自动编辑。 “编辑”基本上是添加一个新行并将数据填充到该行中。向触发器添加一个 1 分钟的计时器可能是个好主意,这样如果要添加大量数据,它就会有时间发生。
- 我离脚本专家还差得很远。我只是浏览其他人制作的不同脚本,并尝试将它们组合起来,让它们为我所需要的工作。我发现脚本会移动一行然后将其删除,但它不会检查要更新的匹配值。我找到了其他检查唯一值并复制的脚本,但它们不会删除另一个 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 处理这些行。
参考资料
我找到了一些与我想要做的很接近的选项,但没有完全匹配的选项。
请求很简单。
"Sheet A" - 硕士 Sheet(有 1 header 行)
"Sheet B" - 输入 Sheet(有 1 header 行)
“C 列”- 唯一 ID(两个 sheet 上的同一列)
触发器
- SheetB编辑
操作数
- 脚本从 C 列的 Sheet B 中找到唯一 ID,并在 C 列的 Sheet A 中查找它。
- 如果找到它,Sheet A 上的 整个相应行 被 替换为 Sheet B. 中的整个相应行
- 如果没有找到,将在 Sheet A 的底部添加一个新行,来自 Sheet B 的 的整个相应行是作为新记录添加到 Sheet A. 底部的新行中
- Sheet B 上的 整个行 已删除。
重复操作,直到从第 2 行开始 Sheet B 中没有填充行(即排除第 1 行 header)。
谢谢
编辑
- 澄清我为什么要这样做。我有一个正在提交的表单,并将数据发送到 Google Sheets(Cognito -> Zapier -> Google Sheets)。此表单的一部分涉及重复部分(行项目)。当前导入响应的方法在正确添加新响应方面没有问题,但是在更新响应时,它无法 find/update 正确地为重复部分添加现有行。所以我就打算用SheetA当我的mastersheet,然后用SheetB简单的当一个receivingsheet。这样我就可以将每个条目(包括更新的条目)作为 Sheet B 上的“新”条目提交,然后让我的脚本进行更新。
- Sheet 每次提交或更新新的表单条目时,B 都会自动编辑。 “编辑”基本上是添加一个新行并将数据填充到该行中。向触发器添加一个 1 分钟的计时器可能是个好主意,这样如果要添加大量数据,它就会有时间发生。
- 我离脚本专家还差得很远。我只是浏览其他人制作的不同脚本,并尝试将它们组合起来,让它们为我所需要的工作。我发现脚本会移动一行然后将其删除,但它不会检查要更新的匹配值。我找到了其他检查唯一值并复制的脚本,但它们不会删除另一个 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 处理这些行。