1

I find a code :

function importRange() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourceSheet = ss.getSheetByName("Sheet1");
  var urlsSheet = ss.getSheetByName("sheet-have-ID");
  var urls = urlsSheet.getRange("rangeID").getValues();
  var j=1;
  for (var i=0;i<urls.length;i++) { 
    if (urls[i][0] != "") {
      var lastrow = SpreadsheetApp.openById(urls[i][0]).getSheetByName("SheetformID").getLastRow();
      var valuesToImport = SpreadsheetApp.openById(urls[i][0]).getSheetByName("Data").getRange(2,1,lastrow,30).getValues();
      var lastrowSource = sourceSheet.getLastRow();
      sourceSheet.getRange(lastrowSource+1,1,lastrow,30).setValues(valuesToImport);
    }
   }
}

It works great, but getting all 30 columns is huge and unnecessary, I just want to get about 15 columns (A, C, D, E, F, AC,.....) in there. Is there any way to do that?

Leti
  • 111
  • 1
  • 8

1 Answers1

3

In your situation, how about the following patterns? In this answer, it supposes that urls is the spreadsheet ID. Please be careful this.

Pattern 1:

In this pattern, the columns of A, C, D, E, F, AC,..... are directly retrieved from the sheet "Data" using Sheets API and the retrieved values are put to the sheet sourceSheet. For this, please modify your script as follows. Before you use this script, please enable Sheets API at Advanced Google services.

From:

for (var i=0;i<urls.length;i++) { 
  if (urls[i][0] != "") {
    var lastrow = SpreadsheetApp.openById(urls[i][0]).getSheetByName("SheetformID").getLastRow();
    var valuesToImport = SpreadsheetApp.openById(urls[i][0]).getSheetByName("Data").getRange(2,1,lastrow,30).getValues();

To:

var columns = ["A", "C", "D", "E", "F", "AC",,,]; // Please set the column letters you want to retrieve.
for (var i=0;i<urls.length;i++) { 
  if (urls[i][0] != "") {
    var ss = SpreadsheetApp.openById(urls[i][0]);
    var lastrow = ss.getSheetByName("SheetformID").getLastRow();
    var sheetName = "Data";
    var v = Sheets.Spreadsheets.Values.batchGet(ss.getId(), {ranges: columns.map(c => `'${sheetName}'!${c}2:${c}${lastrow}`)}).valueRanges.map(({values}) => values.flat());
    var valuesToImport = v[0].map((_, c) => v.map(r => r[c]));
    SpreadsheetApp.flush(); // This might not be required to be used.
    var lastrowSource = sourceSheet.getLastRow();
    sourceSheet.getRange(lastrowSource + 1, 1, valuesToImport.length, valuesToImport[0].length).setValues(valuesToImport);

Pattern 2:

In this pattern, at first, all columns are retrieved. And then, the specific columns are retrieved using the column letters.

From:

for (var i=0;i<urls.length;i++) { 
  if (urls[i][0] != "") {
    var lastrow = SpreadsheetApp.openById(urls[i][0]).getSheetByName("SheetformID").getLastRow();
    var valuesToImport = SpreadsheetApp.openById(urls[i][0]).getSheetByName("Data").getRange(2,1,lastrow,30).getValues();

To:

// Ref: https://stackoverflow.com/a/21231012/7108653
const letterToColumn = letter => {
  let column = 0,
    length = letter.length;
  for (let i = 0; i < length; i++) {
    column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
  }
  return column;
};

var columns = ["A", "C", "D", "E", "F", "AC",,,]; // Please set the column letters you want to retrieve.
var columnIndexes = columns.map(c => letterToColumn(c) - 1);
for (var i=0;i<urls.length;i++) { 
  if (urls[i][0] != "") {
    var ss = SpreadsheetApp.openById(urls[i][0]);
    var lastrow = ss.getSheetByName("SheetformID").getLastRow();
    var v = ss.getSheetByName("Data").getRange(2, 1, lastrow, 30).getValues();
    var temp1 = v[0].map((_, c) => v.map(r => r[c]));
    var temp2 = columnIndexes.map(c => temp1[c]);
    var valuesToImport = temp2[0].map((_, c) => temp2.map(r => r[c]));
    SpreadsheetApp.flush(); // This might not be required to be used.
    var lastrowSource = sourceSheet.getLastRow();
    sourceSheet.getRange(lastrowSource + 1, 1, valuesToImport.length, valuesToImport[0].length).setValues(valuesToImport);

References:

Added:

When I saw your current script in your sample Spreadsheet, I found the following script.

Your current script:

function importRangeAPI() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourceSheet = ss.getSheetByName("KH");
  var urlsSheet = ss.getSheetByName("ZZ");
  var urls = urlsSheet.getRange("B2:B20").getValues(); 
  
  var columns = ["A", "C", "D", "E", "F",,,,]; // Please set the column letters you want to retrieve.
for (var i=0;i<urls.length;i++) { 
  if (urls[i][0] != "") {
    var ss = SpreadsheetApp.openById(urls[i][0]);
    var lastrow = ss.getSheetByName("Data").getLastRow();
    var sheetName = "Data";
    var v = Sheets.Spreadsheets.Values.batchGet(ss.getId(), {ranges: columns.map(c => `'${sheetName}'!${c}2:${c}${lastrow}`)}).valueRanges.map(({values}) => values.flat());
    var valuesToImport = v[0].map((_, c) => v.map(r => r[c]));
    SpreadsheetApp.flush(); // This might not be required to be used.
    var lastrowSource = sourceSheet.getLastRow();
    sourceSheet.getRange(lastrowSource + 1, 1, valuesToImport.length, valuesToImport[0].length).setValues(valuesToImport);
    Sheets.Spreadsheets.Values.batchGet()
}
}
}

In this case, please modify as follows.

  • Please modify var columns = ["A", "C", "D", "E", "F",,,,]; to var columns = ["A", "C", "D", "E", "F"];
  • Please remove Sheets.Spreadsheets.Values.batchGet().

When these are reflected to the script, it becomes as follows.

Modified script:

function importRangeAPI() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourceSheet = ss.getSheetByName("KH");
  var urlsSheet = ss.getSheetByName("ZZ");
  var urls = urlsSheet.getRange("B2:B20").getValues();

  var columns = ["A", "C", "D", "E", "F"]; // Please set the column letters you want to retrieve.
  for (var i = 0; i < urls.length; i++) {
    if (urls[i][0] != "") {
      var ss = SpreadsheetApp.openById(urls[i][0]);
      var lastrow = ss.getSheetByName("Data").getLastRow();
      var sheetName = "Data";
      var v = Sheets.Spreadsheets.Values.batchGet(ss.getId(), { ranges: columns.map(c => `'${sheetName}'!${c}2:${c}${lastrow}`) }).valueRanges.map(({ values }) => values.flat());
      var valuesToImport = v[0].map((_, c) => v.map(r => r[c]));
      SpreadsheetApp.flush(); // This might not be required to be used.
      var lastrowSource = sourceSheet.getLastRow();
      sourceSheet.getRange(lastrowSource + 1, 1, valuesToImport.length, valuesToImport[0].length).setValues(valuesToImport);
    }
  }
}

Note:

  • From your question, unfortunately, I'm not sure about your actual Spreadsheet. Although I tested above script, no error occurs. But, when you tested above script using your actual Spreadsheet, can you provide the sample Spreadsheet for replicating your issue? By this, I would like to confirm it.
Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • Thanks for the reply, what is the Sheets API and why do I have to enable it? Are some functions restricted if the API is not enabled? – Leti Jun 17 '21 at 07:44
  • @Leti Thank you for replying. I apologize for the inconvenience. About Sheets API, you can see the official document. [Ref](https://developers.google.com/sheets/api/reference/rest) In the current stage, Spreadsheet can be managed by Spreadsheet service (SpreadsheetApp) and Sheets API. For most cases, Spreadsheet service can be directly used. But, unfortunately, there are things Spreadsheet service can and cannot do. – Tanaike Jun 17 '21 at 07:51
  • @Leti In your situation, the values of specific columns cannot be directly retrieved with Spreadsheet service. So I used Sheets API. And also, when Sheets API is used, the process cost can be also reduced. [Ref](https://gist.github.com/tanaikech/d102c9600ba12a162c667287d2f20fe4) By the way, I also proposed the method without using Sheets API as the pattern 2. If that was not useful, I apologize again. – Tanaike Jun 17 '21 at 07:51
  • ```Exception: Unexpected error while getting the method or property batchGet on object Apiary.sheets.spreadsheets.values.``` Pattern 1. ```var v = Sheets.Spreadsheets.Values.batchGet(ss.getId(), {ranges: columns.map(c => `'${sheetName}'!${c}2:${c}${lastrow}`)}).valueRanges.map(({values}) => values.flat());``` i have sheet API enabled, is something missing? – Leti Jun 17 '21 at 08:16
  • @Leti Thank you for replying. I apologize for the inconvenience. Unfortunately, I cannot replicate your situation of `Unexpected error while getting the method or property batchGet on object Apiary.sheets.spreadsheets.values.`. In my test, I can confirm that the script works. This is due to my poor skill. I deeply apologize for my poor skill. In order to correctly understand about your situation, can you provide the sample Spreadsheet and your current script for replicating your issue? By this, I would like to confirm it. – Tanaike Jun 17 '21 at 08:42
  • https://docs.google.com/spreadsheets/d/13p4xrIfACk_l_oRgBnDr8VaOtEL9o4SxeIql5eqryOc/edit#gid=1930684987. of course – Leti Jun 17 '21 at 08:53
  • @Leti Thank you for replying. Unfortunately, it seems that your sample Spreadsheet has no values. By this, I cannot replicate your situation of `Unexpected error while getting the method or property batchGet on object Apiary.sheets.spreadsheets.values.`. This is due to my poor skill. I deeply apologize for my poor skill. In order to correctly understand about your situation, can you provide the sample Spreadsheet including the sample values and your current script for replicating your issue? By this, I would like to confirm it. – Tanaike Jun 17 '21 at 08:58
  • 1
    @Leti Now, I added the modified script from your current script in your sample Spreadsheet. Could you please confirm it? From your question, unfortunately, I'm not sure about your actual Spreadsheet. Although I tested above script, no error occurs. But, when you tested above script using your actual Spreadsheet, can you provide the sample Spreadsheet for replicating your issue? By this, I would like to confirm it. – Tanaike Jun 17 '21 at 09:26
  • I just tried it, it ran and pasted the data successfully (4000 rows), but 3 runs got 1 partial paste (2000 rows). then the script ends with the error ```TypeError: Cannot read property 'flat' of undefined @ code.gs:13```, sorry so much spreadsheet I don't know how to share it all – Leti Jun 17 '21 at 09:48
  • i know why ```["AE","A","R","D","B","C","F","H","K","L","O","Q","G","P","E"]```. Because ```AE``` it seems to be understood only up to the 26th column. – Leti Jun 17 '21 at 09:58