使用 GAS batchUpdate 将数据从 Google Sheets Custom 表单上的特定单元格复制到同一 Spreadsheet 中不同 sheet 上的特定行

Using GAS batchUpdate to copy data from specific cells on a Google Sheets Custom form to a specific row on a different sheet in the same Spreadsheet

我又陷入困境了。最后一个问题是关于将 spreadsheet:sheet 行中的值写入自定义表单(源自 sheet )上的特定单元格的加速。 这一次,我试图做相反的事情...将数据从表单上的单元格列表复制到数据sheet 上的特定行。 'push' 数据到数组的语句有效。然后,当我 运行 我无法理解的 batchUpdate 代码(如下)时,我得到一个错误。任何帮助,将不胜感激。 ...或者我应该恢复为逐项从数组复制到数据sheet(~5秒)?

“错误
GoogleJsonResponseException:API 调用 sheets.spreadsheets.values.batchUpdate 失败,出现错误:'data[0]' 处的值无效(type.googleapis。com/google。apps.sheets。v4.ValueRange ), "5693123-Q5aa" 'data[1]' (type.googleapis.com/google.apps.sheets.v4.ValueRange) 处的无效值,“Fredi” 'data[2]' 处的值无效(type.googleapis.com/google.apps.sheets.v4.ValueRange),“酵母” ...随后是每个数据单元格的另外 53 行类似消息。"enter code here

//** Function to copy data from the specific cells of the User form ("User Contact Info Form") to the spreadsheet sheet ("VolunteerListTbl") into Row# (DatabaseRow2Update) */
function Ex_UpdateRecord(){

  var Ss=SpreadsheetApp.getActiveSpreadsheet();
  var ShUserForm=Ss.getSheetByName("User Contact Info Form");
  var DataSheet = Ss.getSheetByName("VolunteerListTbl");
  var DatabaseRow2Update = ShUserForm.getRange("A11").getValue();
  var LastColNumber = DataSheet.getLastColumn(); 

  var RangesToUpdate = ["C11", "F10", "B10", "B14", "B16", "B12", "C17", "F14", "F15", "I10", "I12", "I14", "I16", "F17", "B19", "F20", "I20", "F22", "I22", "F24", "C27", "B22", "C23", "B24", "B26", "F28", "C29", "B28", "B34", "B32", "G32", "G36", "C36", "B40", "B42", "E40", "H40", "E42", "H42", "B44", "E44", "H44", "E46", "H46", "C48", "B52", "B54", "F52", "B56", "F54", "F56", "F11", "C17",  "D19", "D20"]; //List of cells containing data to be updated on the "VolunteerListTbl" sheet

  //Routine to create the array of values to be used to update the sheet's row values
  var FormValuesArray = [];
  for (var j=0; j<RangesToUpdate.length; j++){ //this loop will add each successive value for the cells listed above...to fill the array (1x56 values)
    FormValuesArray.push(ShUserForm.getRange(RangesToUpdate[j]).getValue());
    
    Logger.log("Array value for j= " + j + "; is " + ShUserForm.getRange(RangesToUpdate[j]).getValue() + " for the range " + RangesToUpdate[j])
  }
  
  DataSheet.getRange(DatabaseRow2Update,1,1,LastColNumber).activate();//Added this to specify the row where the data was to be updated
  Sheets.Spreadsheets.Values.batchUpdate({data: FormValuesArray, valueInputOption: "USER_ENTERED"}, Ss.getId());

  return  
}

我相信你的目标如下。

  • 您想将 sheet“用户联系信息表单”中 RangesToUpdate 范围内的值复制到 sheet“VolunteerListTbl”中的相同范围内的值。
  • 您想使用表格实现此目的 API。

当我看到你的脚本时,FormValuesArray.push(ShUserForm.getRange(RangesToUpdate[j]).getValue());是循环使用的。在这种情况下,工艺成本变高。为此,我想建议使用 Sheets API.

检索值

而且,关于你的这个脚本 Sheets.Spreadsheets.Values.batchUpdate({data: FormValuesArray, valueInputOption: "USER_ENTERED"}, Ss.getId());,似乎 FormValuesArray 是一个类似于 ["value1", "value2",,,] 的数组。 spreadsheets.values.batchUpdate方法的请求体是{"data": [{"range": "", "values": []}]}Ref 我认为这可能是您遇到问题的原因。在您的请求正文中,需要设置范围和值属性。

当以上几点反映到你的脚本中,就会变成下面这样。

修改后的脚本:

function Ex_UpdateRecord() {
  var Ss = SpreadsheetApp.getActiveSpreadsheet();
  var ssId = Ss.getId();
  var srcSheetName = "User Contact Info Form";
  var dstSheetName = "VolunteerListTbl";
  var RangesToUpdate = ["C11", "F10", "B10", "B14", "B16", "B12", "C17", "F14", "F15", "I10", "I12", "I14", "I16", "F17", "B19", "F20", "I20", "F22", "I22", "F24", "C27", "B22", "C23", "B24", "B26", "F28", "C29", "B28", "B34", "B32", "G32", "G36", "C36", "B40", "B42", "E40", "H40", "E42", "H42", "B44", "E44", "H44", "E46", "H46", "C48", "B52", "B54", "F52", "B56", "F54", "F56", "F11", "C17", "D19", "D20"];

  // Retrieve values from "dstSheetName".
  var values = Sheets.Spreadsheets.Values.batchGet(ssId, { ranges: RangesToUpdate.map(e => `'${srcSheetName}'!${e}`) });
  
  // Create a request body.
  var FormValuesArray = values.valueRanges.map((e, i) => ({ range: `'${dstSheetName}'!${RangesToUpdate[i]}`, values: e.values }));

  // Put the values to "VolunteerListTbl".
  Ss.getSheetByName(dstSheetName).getRange(DatabaseRow2Update, 1, 1, LastColNumber).activate();
  Sheets.Spreadsheets.Values.batchUpdate({ data: FormValuesArray, valueInputOption: "USER_ENTERED" }, ssId);
}
  • 在此修改后的脚本中,“用户联系信息表单”sheet 中 RangesToUpdate 的范围被复制到“VolunteerListTbl”sheet 中 RangesToUpdate 的相同范围].

参考文献:

已添加 1 个:

根据您的以下回复,

The number of data fields from the source (the "User Contact Info Form") and the destination are the same. It is the locations on the sheets that differ. For example, cell C11 on the form copies to column 1 on the destination sheet ("VolunteerListTbl") and cell F10 on the form copies to column 2 on "VolunteerListTbl"... and so on. The arrangement on the form was due to groupings that allowed a cohesive display. The RangesToUpdate (source) are in the same order as the cells on the destination table. Thanks for making the effort to clarify.

我认为您想将这些值放在 sheet“VolunteerListTbl”中的一行中。在这种情况下,下面的修改脚本怎么样?

修改后的脚本:

function Ex_UpdateRecord() {
  var Ss = SpreadsheetApp.getActiveSpreadsheet();
  var ssId = Ss.getId();
  var srcSheetName = "User Contact Info Form";
  var dstSheetName = "VolunteerListTbl";
  var RangesToUpdate = ["C11", "F10", "B10", "B14", "B16", "B12", "C17", "F14", "F15", "I10", "I12", "I14", "I16", "F17", "B19", "F20", "I20", "F22", "I22", "F24", "C27", "B22", "C23", "B24", "B26", "F28", "C29", "B28", "B34", "B32", "G32", "G36", "C36", "B40", "B42", "E40", "H40", "E42", "H42", "B44", "E44", "H44", "E46", "H46", "C48", "B52", "B54", "F52", "B56", "F54", "F56", "F11", "C17", "D19", "D20"];

  // Retrieve values from "dstSheetName".
  var values = Sheets.Spreadsheets.Values.batchGet(ssId, { ranges: RangesToUpdate.map(e => `'${srcSheetName}'!${e}`) });
  
  // Create an array for putting to spreadsheet.
  var FormValuesArray = values.valueRanges.map(e => e.values[0][0]);

  // Put the values to "VolunteerListTbl".
  var dstSheet = Ss.getSheetByName(dstSheetName);
  dstSheet.getRange(1, 1, 1, FormValuesArray.length).setValues([FormValuesArray]);
  // or dstSheet.appendRow(FormValuesArray);
}
  • 在此脚本中,从 User Contact Info Form 检索到的值被放入 sheet VolunteerListTbl 的一行。
  • 在这种情况下,使用 setValuesappendRow 放置值。
  • 如果要将行附加到目标 sheet,请使用 dstSheet.appendRow(FormValuesArray)

添加了 2 个:

当我看到您的示例 Spreadsheet 时,我注意到您的目的地 sheet 名称是 VolSearchResult Tbl。但是您的脚本使用 VolunteerListTbl。我认为这可能是您遇到问题的原因。而且,我测试了我的示例脚本,反映了我评论中建议的修改,我确认没有错误发生。为此,请测试以下脚本。

示例脚本:

function Ex_UpdateRecord() {
  var Ss = SpreadsheetApp.getActiveSpreadsheet();
  var ssId = Ss.getId();
  var srcSheetName = "User Contact Info Form";
  var dstSheetName = "VolSearchResult Tbl";
  var RangesToUpdate = ["C11", "F10", "B10", "B14", "B16", "B12", "C17", "F14", "F15", "I10", "I12", "I14", "I16", "F17", "B19", "F20", "I20", "F22", "I22", "F24", "C27", "B22", "C23", "B24", "B26", "F28", "C29", "B28", "B34", "B32", "G32", "G36", "C36", "B40", "B42", "E40", "H40", "E42", "H42", "B44", "E44", "H44", "E46", "H46", "C48", "B52", "B54", "F52", "B56", "F54", "F56", "F11", "C17", "D19", "D20"];

  // Retrieve values from "dstSheetName".
  var values = Sheets.Spreadsheets.Values.batchGet(ssId, { ranges: RangesToUpdate.map(e => `'${srcSheetName}'!${e}`) });
  
  // Create an array for putting to spreadsheet.
  var FormValuesArray = values.valueRanges.map(e => e.values && e.values[0] ? e.values[0][0] : ""); // This modification is from my comment.

  // Put the values to "VolSearchResult Tbl".
  var dstSheet = Ss.getSheetByName(dstSheetName);
  dstSheet.appendRow(FormValuesArray);
}

根据 Tanaike 的建议,开发了一种解决方案,可将执行时间从约 1300 毫秒减少到约 400-600 毫秒。有效的代码(适用于我的应用程序,用于将修改后的数据复制到 Google Apps 脚本中的 2 个不同的表)显示在代码行中。最后两行可以互换,第一行用于更新现有记录,第二行(使用 'append' 方法)用于添加新记录。

  var srcSheetName = "User Contact Info Form";// 'Source' sheet name
  var dstSheetName = "Volunteer List Tbl"; // 'Destination' sheet name was "VolunteerListTbl";
  var dstSheet2Name = "VolSearchResult Tbl"; // 'Destination' sheet name was "VolunteerListTbl";

// Retrieve values from "srcSheetName" (source)
  var values = Sheets.Spreadsheets.Values.batchGet(ssId, { ranges: FormRangesToCopy.map(e => `'${srcSheetName}'!${e}`) });

// Create an array for putting to spreadsheet. /// Method 2
  var FormValuesArray = values.valueRanges.map(e => e.values && e.values[0] ? e.values[0][0] : ""); // This modification is from my comment.

// Copy the values to "Volunteer List Tbl".
  var dstSheet = Ss.getSheetByName(dstSheetName);
  var dstSheet2 = Ss.getSheetByName(dstSheet2Name);
  dstSheet.getRange(DataSheetRowDisplayed,1,1,FormValuesArray.length).setValues([FormValuesArray]); //Worked!!!
  dstSheet2.getRange(SearchRowDisplayed,1,1,FormValuesArray.length).setValues([FormValuesArray]); //Worked!!!

// OR Append a new record to table  
//a  dstSheet.appendRow(FormValuesArray); //Append Row adds a 'New' row.