0

I would like to develop a script that allows to apply the same function in column A while refering to all the rows below (from A1 to A600) that is a Query(Importrange) for which the number of rows to be inserted is not fixed (from 1 to 300) and so has to be inserted before copying the data.

I started by developing a formula in cell A1 that is working very well but that implies to copy the block 600 times in the cell to cover all the lines :

`={Query(IMPORTRANGE('Master Table Projects'!T503,"Impacted Formula!A5:R1000"),"where Col1 is not Null");Query(IMPORTRANGE('Master Table Projects'!T467,"Impacted Formula!A5:R1000"),"where Col1 is not Null");Query(IMPORTRANGE('Master Table Projects'!T15,"Impacted Formula!A5:R1000"),"where Col1 is not Null")}

By consequence, I have to develop a script with a loop to look apply this formula from T1 to T600. I tried this :

function myFunction() {
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
var searchRange = sheet.getRange(2,2, lastRow-1, lastColumn-1);
  for (r=1; r<100;r++) {
    var sa=(Query(IMPORTRANGE('Master Table Projects'!Tr,"Impacted Formula!A5:R1000"),"where Col1 is not Null")); 
   ss.getRange(r,1).setValue(sa); 
  };

This is not working since I receive an alert message : "SyntaxError: missing ) after argument list (line 19, file "learnings.gs")"

I'm not an expert at all in programmation but : I suppose that my "var sa" is not set up properly but I have no idea how to correct it. Tr means for me "T1 to T600" but most probably it's not well written.

I'm attaching a picture of the results I would like to get : expected results

By adding the code line proposed by @ziganotschka

sheet.getRange("A" + sheet.getLastRow()).setValue(sa);

I got the results attached in the new picture that is a nice improvement because are only appearing the imported rows that have some results to display but : There is still the issue of overlapping of data imported. And the last line (that corresponds to T999) has to be removed manually to see some of the results.improved macro

If you click on the link of the spreadsheet I can give you access afterwards but I cannot share a public link due to my company restrictions (this option is blocked).

Can you please help me by correcting these lines to make it work ?

Thanks to @ziganotschka here is the working code :

  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var limit = ss.getSheetByName('Master Table Projects').getRange("T2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
  Logger.log(limit);
  for (var r=2; r<=limit; r++) { 
    var sa="=Query(IMPORTRANGE('Master Table Projects'!T"+r+',"Impacted Formula!A5:R1000"),"where Col1 is not Null")'; 
    var firstEmptyRow = sheet.getRange("A1").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()+1;
      Logger.log(firstEmptyRow);
    sheet.getRange("A" + firstEmptyRow).setValue(sa);
    SpreadsheetApp.flush();
  }
}

Thanks so much Isa

Isabelle
  • 13
  • 4
  • Before helping you with the script part, Ineed to understand your formula. The syntaxt for `IMPORTRANGE` is `=IMPORTRANGE(spreadsheet_url, range_string)` but I do not see any `url` in your formula. – ziganotschka Jul 03 '20 at 10:19
  • Master Table Projects is a tab in the same google sheet – Isabelle Jul 05 '20 at 18:39
  • Does the solution with `getLastRow()` as mentioned int he comment to my answer solve the issue? Otherwise please provide access to a sample sheet. – ziganotschka Jul 08 '20 at 13:32
  • @ziganotschka I have updated my question with the improvements brought by your solution with getLastRow() but that is not solving the issue of overlapping of data from a row to another – Isabelle Jul 09 '20 at 11:59
  • As already mentioned, I would need to have a look at your spreadsheet including the data in `Master Table Projects` and `Impacted Formula` to find a solution for your case. – ziganotschka Jul 09 '20 at 12:26
  • can you please click on the link and I will give you the access ? – Isabelle Jul 09 '20 at 15:30
  • Did you see the updated answer? – ziganotschka Jul 13 '20 at 07:13
  • I saw that you created myFunction3() that is giving in cell A2 all the imported ranges until r=5 since the code is saying r<6. This means that the loop is not looking to the last active row that can be row 3 or row 600 with the real file (here I shared with you a small example with 3 lines to be looked at only). Do you think there is a way to have the r<10000 but the loop stopping in case there is nothing after line 7 for example ? – Isabelle Jul 13 '20 at 08:14
  • An other thing is that if among the imported ranges one file is not filled or not present, is it possible to have a line created with NA ? Currently if one file cannot be imported then nothing is appearing in cell A2 with an error printed since the whole function is appearing in cell A2. – Isabelle Jul 13 '20 at 08:20
  • What would be great is to have in cell A2 the imported range of T2 with the needed rows to be imported, in the next available cell A3 (or A>3 if several lines were added with T2) the imported range T3 with the number of lines needed for this import etc... And if T4 is empty then to have either a NA in all the cells or to skip this import to go to T5 and insert what is needed. – Isabelle Jul 13 '20 at 08:20
  • I see, I updated my answer providing you two working solutions for your case implementing dynamic finding of the last entry in column T. This should solve your issue. – ziganotschka Jul 13 '20 at 08:58
  • Thank you so much. I tried myFunction3() and this is working very well if all the files in Tx are correct. But if one file is missing then the whole formula stops and #VALUE! is appearing. I have added some lines in the master table : only line 6 is not containing the correct file all the others including line 7 have files to be imported. – Isabelle Jul 13 '20 at 12:51
  • When trying myFunction4() nothing is appearing on the page. – Isabelle Jul 13 '20 at 12:52
  • It worked before and it works again after I eliminated the 1000 empty rows that were for some reason in the sheet now. Make sure that you clean empty rows before runing the script (you can also dit programmatically as shown [here](https://stackoverflow.com/a/62229456/11599789)). Also, with your data structure, please change `sheet.getRange("A2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()+1;` to `sheet.getRange("A1").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()+1;` – ziganotschka Jul 13 '20 at 13:17
  • 1
    @ziganotschka thanks a lot for your explanation. I'm out of the office for some days, I will check when back on Saturday. I would like to thank you warmly for all your help until now. – Isabelle Jul 15 '20 at 07:59
  • 1
    @ziganotschka I confirm that "myFunction4()" is working perfectly.Thanks ! – Isabelle Aug 10 '20 at 15:34
  • I indeed would like to delete all the rows before running the macro whatever they have content or they are empty so I tried to use the link shared but I got the error message : "ReferenceError: range is not defined" – Isabelle Aug 10 '20 at 16:51

1 Answers1

0

Provide that you have a working formula, in order to assign it with a dynamic row index, you need to concatenate it correctly:

  • When you build your variable sa, it can be composed of references to other variables and text
  • The text must be designated as a string by wrapping in=t in single or double quotes
  • If you text (formula) already contains some quotes, make sure to adapt the outer wrapping quotes to assure an alternation of single (') and double (") quotes or escape quotes - see here
  • For formulas, = should be part of the text
  • To concatentate the text part and the variable reference, use the + sign
  • Your IMPORTRANGE formula might return you empty rows, you have to query for the next free row each time you set a new formula.
  • Useful for this is the method getNextDataCell()

Sample:

function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var limit = ss.getSheetByName('Master Table Projects').getRange("T2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
  for (var r=2; r<=limit; r++) { 
    var sa="=Query(IMPORTRANGE('Master Table Projects'!T"+r+',"Impacted Formula!A5:R1000"),"where Col1 is not Null")'; 
    var firstEmptyRow = sheet.getRange("A2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()+1;
    sheet.getRange("A" + firstEmptyRow).setValue(sa);
    SpreadsheetApp.flush();
  }
}

Notes:

  • It is not good practice to use setValue() in each single line, for the future consider storing the requests in an array and assgin after exiting the for loop all the values at one to the spreadsheet with setValues()
  • Double-check if your formula is correct (IMPORTRANGE expects a URL to a spreadhsheet)

Update

  • To make sure that the formulas don't overwrite each other, you can implement: sheet.getRange("A" + sheet.getLastRow()+1).setValue(sa);
  • However, in your case the importrange creates empty rows that are not being script inspite of the query "where Col1 is not Null".
  • Thus, it's best to concatenate all the queries with ; and set them into the same cell
  • If you want to retrieve the last row og column T in sheet 'Master Table Projects' dynamically, you can implement

var limit = ss.getSheetByName('Master Table Projects').getRange("T2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();

and then loop until limit

Sample:

function myFunction2() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var sa="={";
  var limit = ss.getSheetByName('Master Table Projects').getRange("T2").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
  for (var r=2; r<limit; r++) { 
    var sa1="Query(IMPORTRANGE('Master Table Projects'!T"+r+',"Impacted Formula!A5:R1000"),"where Col1 is not Null")';
    sa=sa+sa1+";";
  }
  sa = sa.slice(0,-1) +"}";
  sheet.getRange("A2").setValue(sa);
}
ziganotschka
  • 25,866
  • 2
  • 16
  • 33
  • Thanks a lot for your help ! This is almost what I was looking for except that with this code the formula is written in each cell of column A but without adding the number of rows needed at each insertion and so if there is more than one line to be added then it's not working due to overwritting of the data below.The idea would be to have this fonction in cell A2 only but with the complete loop looking at each cell : T1 to T600. – Isabelle Jul 05 '20 at 19:05
  • I just tried : for (var r=1; r<1000;r++) { var sa="=(Query(IMPORTRANGE('Master Table Projects'!T"+r+',"Impacted Formula!A5:R1000"),"where Col1 is not Null"))'; sa=sa&sa; sheet.getRange("A2").setValue(sa); But this is only printed the value of T999 in cell A2 and not the concatener of cells T1 to T999 in A2 – Isabelle Jul 05 '20 at 19:25
  • Can you provide a sample spreadsheet with your data? And maybe a screenshot of the desired output? – ziganotschka Jul 06 '20 at 07:50
  • here it is: https://docs.google.com/spreadsheets/d/1KyH2d6PouzoLULrC_JGw_FroejPhQTmFVL0jpRcut00/edit#gid=40462952 – Isabelle Jul 06 '20 at 17:48
  • You need to make it accessible. – ziganotschka Jul 07 '20 at 07:03
  • According to the additional information your provided, please try if `sheet.getRange("A" + sheet.getLastRow()).setValue(sa); ` works for you. Some query formulas might create a problem by creating additional empty rows, I cannot test it in your case without access to your spreadsheet. – ziganotschka Jul 08 '20 at 09:46