如何通过CRUD操作修改Google Sheets表格?(附实操案例)
在Google Sheets中基于CRUD指令批量修改表格数据
这里提供两种实用方案,分别适合普通用户和需要自动化/直接修改原表的场景:
方案一:公式法(无需代码,生成新结果表)
适合不想写脚本、希望实时同步修改结果的场景,最终结果生成在新工作表中,不修改原Table1。
前提假设
- Table1在
Sheet1,数据范围为A:E(前5列为匹配主键,后续为数据列),第一行是表头 - Table2在
Sheet2,数据范围为A:F(前5列与Table1一致,第F列为Action,取值为CREATE/UPDATE/DELETE),第一行是表头
操作步骤
- 新建一个工作表(比如命名为
Result) - 在
Result!A1单元格输入以下公式:
=LET( table1, Sheet1!A:E, table2, Sheet2!A:F, // 提取所有需要删除的主键(前5列拼接) delete_keys, FILTER(table2!A:E, table2!F:F="DELETE"), delete_key_strs, ARRAYFORMULA(INDEX(delete_keys,0,1)&"|"&INDEX(delete_keys,0,2)&"|"&INDEX(delete_keys,0,3)&"|"&INDEX(delete_keys,0,4)&"|"&INDEX(delete_keys,0,5)), // 过滤Table1中未被标记删除的行 filtered_table1, FILTER(table1, NOT(COUNTIF(delete_key_strs, INDEX(table1,0,1)&"|"&INDEX(table1,0,2)&"|"&INDEX(table1,0,3)&"|"&INDEX(table1,0,4)&"|"&INDEX(table1,0,5))>0)), // 提取所有需要更新的行 update_rows, FILTER(table2!A:E, table2!F:F="UPDATE"), update_key_strs, ARRAYFORMULA(INDEX(update_rows,0,1)&"|"&INDEX(update_rows,0,2)&"|"&INDEX(update_rows,0,3)&"|"&INDEX(update_rows,0,4)&"|"&INDEX(update_rows,0,5)), // 匹配并更新filtered_table1中的对应行 updated_table, ARRAYFORMULA(IFERROR(VLOOKUP(INDEX(filtered_table1,0,1)&"|"&INDEX(filtered_table1,0,2)&"|"&INDEX(filtered_table1,0,3)&"|"&INDEX(filtered_table1,0,4)&"|"&INDEX(filtered_table1,0,5), update_key_strs&"|"&INDEX(update_rows,0,1)&"|"&INDEX(update_rows,0,2)&"|"&INDEX(update_rows,0,3)&"|"&INDEX(update_rows,0,4)&"|"&INDEX(update_rows,0,5), {2,3,4,5,6}, FALSE), filtered_table1)), // 提取所有需要新增的行 create_rows, FILTER(table2!A:E, table2!F:F="CREATE"), // 合并更新后的表和新增行 final_result, {updated_table; create_rows}, final_result )
- 按回车键后,
Result表会自动生成处理后的最终数据
核心逻辑
- 先移除Table1中被Table2标记为
DELETE的行 - 用Table2中
UPDATE的行替换Table1中主键匹配的行数据 - 最后追加Table2中标记为
CREATE的新行
注意事项
- 前5列的组合必须是唯一主键,否则会出现匹配错误
- 公式会实时同步Table1和Table2的修改,无需手动刷新
- 如果你的表格列数或工作表名称不同,需要对应调整公式中的引用范围
方案二:Apps Script脚本法(直接修改原Table1)
适合需要直接修改原表、批量处理大量数据,或需要自动化执行的场景。
操作步骤
- 打开目标Google Sheets文档,点击「扩展程序」→「Apps Script」
- 删除默认代码,粘贴以下脚本:
function applyCRUD() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const table1 = ss.getSheetByName("Sheet1"); // 替换为你的Table1工作表名称 const table2 = ss.getSheetByName("Sheet2"); // 替换为你的Table2工作表名称 // 获取数据(跳过表头,若没有表头则删除.slice(1)) const table1Data = table1.getDataRange().getValues().slice(1); const table2Data = table2.getDataRange().getValues().slice(1); // 构建Table1的主键映射:主键字符串 → 行号 const table1KeyMap = new Map(); table1Data.forEach((row, idx) => { const key = row.slice(0, 5).join("|"); // 用|拼接前5列作为唯一键 table1KeyMap.set(key, idx + 2); // 行号从2开始(跳过表头) }); // 1. 处理UPDATE操作 table2Data.forEach(row => { const action = row[5]; if (action !== "UPDATE") return; const key = row.slice(0, 5).join("|"); if (table1KeyMap.has(key)) { const rowNum = table1KeyMap.get(key); // 写入更新后的数据(前5列) table1.getRange(rowNum, 1, 1, 5).setValues([row.slice(0, 5)]); } }); // 2. 处理DELETE操作(倒序删除避免行号偏移) const deleteKeys = table2Data .filter(row => row[5] === "DELETE") .map(row => row.slice(0, 5).join("|")); const rowsToDelete = []; table1Data.forEach((row, idx) => { const key = row.slice(0, 5).join("|"); if (deleteKeys.includes(key)) { rowsToDelete.push(idx + 2); } }); // 倒序删除行,防止删除前面的行导致后面的行号错位 rowsToDelete.sort((a, b) => b - a).forEach(rowNum => table1.deleteRow(rowNum)); // 3. 处理CREATE操作 const createRows = table2Data .filter(row => row[5] === "CREATE") .map(row => row.slice(0, 5)); if (createRows.length > 0) { const lastRow = table1.getLastRow(); table1.getRange(lastRow + 1, 1, createRows.length, 5).setValues(createRows); } }
- 修改脚本中的工作表名称(
Sheet1和Sheet2)为你实际的表名 - 点击工具栏的「运行」按钮,首次运行需要授权权限,按照提示完成授权即可
核心逻辑
- 先遍历Table2的
UPDATE指令,匹配Table1的主键并更新对应行 - 收集所有需要删除的行号,倒序删除避免行号偏移问题
- 最后将
CREATE指令的新行追加到Table1末尾
进阶优化
- 可以设置时间驱动触发器,让脚本定时自动执行
- 若需要监听表格修改自动执行,可设置onChange触发器
内容的提问来源于stack exchange,提问作者thdox
相关产品推荐
相关产品推荐

