Google spreadsheet script time limit of execution - google-apps-script

I've written gs script to clear data from all cells in sheets. Spreadsheet has a lot of sheets (about 200) and I get error of time limit execution. Maybe somebody have ideas how to resolve this issue. Here example of my code.
function cleanAllOld() {
var sheetsName = new Array();
var destination = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/link");
var sheets = destination.getSheets();
for (var k = 0; k < sheets.length; k++) {
sheetsName.push([sheets[k].getName()]);
for (var p = 0; p < sheetsName.length; p++) {
var sheet = destination.getSheetByName(sheetsName[p]);
if (sheet === null) {} else {
sheet.getDataRange().clearContent();
}
}
}
}

I don't get all the part of your code, but I think he's too complicated for nothing. Here's is a sample which work:
function AllDelete() {
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/link");
var sheets = ss.getSheets();
var i = 0;
for(i in sheets){
sheets[i].clearContents();
}
}
Edit: Max is fast and is right, the getDataRange() method is using a lot of ressources

I think the problem is geting data range.
Try replace this
sheet.getDataRange().clearContent();
by this:
sheet.clearContents();

Related

Delete all Sheets except one, loop within a loop

I have a spreadsheet that contains a list of URLS for spreadsheets and the sheet name that I want to keep.
The idea is that I delete all sheets within each of those spreadsheets except the sheet I want to keep.
I have written a script but I can not seem to get it to work, I get an error message of "invalid argument line 20" but I can not figure out why.
I have pasted my code below, any help would be appreciated.
function DeleteImportedData(){
var s3 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("URL's")
var s1 = SpreadsheetApp.getActiveSpreadsheet()
var sh1 = s1.getSheetByName("MasterSheet")
var copy = sh1.getRange(1,1,sh1.getLastRow(),sh1.getLastColumn()).getValues()
var getHeader = sh1.getRange(1,1,1,25).getValues()
for (var j = 1;j<s3.getLastRow(); j++){
var filterName = s3.getRange(j+1, 1).getValue()
var id = s3.getRange(j+1,2).getValue()
var open = SpreadsheetApp.openById(id)
var sheet = open.getSheets()[0];
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sh3 = open.getSheetByName("STSOR - "+filterName)
}
for (i = 0; i <= sheets.length; i++) {
switch(sheets[i]) {
case sheet.getSheetName() === sh3:
break;
default:
open.setActiveSheet(sheet[i]);
open.deleteActiveSheet;
open.deleteSheet(del)
}
}
}
when you delete the first sheet from the list Sheet1, Sheet2, Sheet3 - Sheet2 changes its index to Sheet1. So it is better to delete sheets from the end
try to use the reverse loop
for (i = sheets.length-1; i >=0 ; i--){
... your code ...
}
There is something wrong between your variable sheet and sheets and your second loop.
Try this way :
for (var j = 1;j<s3.getLastRow(); j++){
// your code
// second loop inside the first loop
for (i = 0; i <= sheets.length; i++) {
switch(sheets[i]) {
case sheets[i].getSheetName() === sh3: //instead of 'sheet'
break;
default:
open.setActiveSheet(sheets[i]); //instead of 'sheet'
open.deleteActiveSheet;
open.deleteSheet(del)
}
} // close first loop
} // close second loop
but I think the second loop would be cleaner that way (IMHO):
for (i = 0; i <= sheets.length; i++) {
if (sheets[i].getSheetName() !== sh3) {
open.deleteSheet(sheets[i].getSheetName());
}
}
If this code doesn't answer your question, please provide more informations about your spreadsheets

How do I solve 'Those rows are out of bounds.' on Google Sheets?

This is the script I have currently. I just picked up script editing recently and I cant resolve this issue.
I am trying to delete the same row in 2 sheets.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Verification');
var r = s.getRange('Q:Q');
var v = r.getValues();
for(var i=v.length-1;i>=0;i--)
if(v[0,i] == 'Cancelled')
s.deleteRow(i+1);
ss.getSheetByName('S4 Branch');
s.deleteRow(i+1);
I believe your goal as follows.
You want to check the values of the column "Q" of "Verification" sheet.
When the value is Cancelled, you want to delete the row, and also, you want to delete the row of the same row number in "S4 Branch" sheet.
Modification points:
If you want to compare the value of Cancelled with v, please modify if(v[0,i] == 'Cancelled') to if(v[i][0] == 'Cancelled').
When var r = s.getRange('Q1:Q' + s.getLastRow()); is used as the data range instead of var r = s.getRange('Q:Q');, the process cost will be able to be reduced a little.
In your script, the if statement and the for loop are not enclosed by { and }. By this, each script is used for just under the line. For example, for(var i=v.length-1;i>=0;i--) is used for if(v[0,i] == 'Cancelled'). And, if(v[0,i] == 'Cancelled') is used for s.deleteRow(i+1);. By this, i at s.deleteRow(i+1); is always -1. So s.deleteRow(0); is run. In this case, an error occurs. I think that this might be the reason of your issue.
When above points are reflected to your script, it becomes as follows.
Modified script:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Verification');
var r = s.getRange('Q1:Q' + s.getLastRow());
var v = r.getValues();
var s2 = ss.getSheetByName("S4 Branch");
for (var i = v.length - 1; i >= 0; i--) {
if (v[i][0] == 'Cancelled') {
s.deleteRow(i + 1);
s2.deleteRow(i + 1);
}
}
}
References:
getLastRow()
deleteRow(rowPosition)
If you want to try the below script:
You can add more sheets by updating the sheetArr list and it can auto-trigger on Edit.
function onEdit() {
deleteRow();
}
function deleteRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetArr = ['Verification', 'S4 Branch'];
for (var i = 0; i<sheetArr.length; i++){
var lr = ss.getSheetByName(sheetArr[i]).getDataRange().getLastRow();
var s = ss.getSheetByName(sheetArr[i]).getRange('Q1:Q' + lr ).getValues();
for (var j = s.length -1; j >= 0; j--){
if (s[j] == 'Cancelled'){
delrow = ss.getSheetByName(sheetArr[i]).deleteRow(j+1);
}
}
}
}

Import sheets from folder into master, optimize code to avoid runtime error row by row

There is a code here that loads data from spreadsheets in one folder into a master sheet. Then it does a check and pushes values to the folder sheets so that there are no duplicates being sent over.
The issue I experience is that I am having to do this with over 50k values, and may often run into runtime errors.
How should this be modified to avoid going row by row?
function getDataToMaster() {
var folder = DriveApp.getFolderById("111p5daTNJkyDL5vf0TmiKuqtQBjz8ryL"); //Define id of folder
var contents = folder.getFiles();
var file;
var data;
var sheetMaster = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
while(contents.hasNext()){
file = contents.next();
if (file.getMimeType() == "application/vnd.google-apps.spreadsheet") {
var sheet = SpreadsheetApp.openById(file.getId()).getSheetByName("Sheet1");
var startRow = 2;
var data = sheet.getDataRange().getValues();
var colToCheck = 6;
for(var j = 1; j < data.length;j++){
if(data[j][colToCheck-1] != "copied"){
sheetMaster.appendRow(data[j]);
sheet.getRange((j+1), colToCheck).setValue("copied");
SpreadsheetApp.flush();
}
}
}
}
}
You want to reduce the process cost for putting values to Spreadsheet.
You want to improve the following part.
for(var j = 1; j < data.length;j++){
if(data[j][colToCheck-1] != "copied"){
sheetMaster.appendRow(data[j]);
sheet.getRange((j+1), colToCheck).setValue("copied");
SpreadsheetApp.flush();
}
}
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification point:
In order to reduce the process cost of above part, I propose to use setValues instead of appendRow and setValue. Ref
Modified script:
When your script is modified, it becomes as follows.
From:
for(var j = 1; j < data.length;j++){
if(data[j][colToCheck-1] != "copied"){
sheetMaster.appendRow(data[j]);
sheet.getRange((j+1), colToCheck).setValue("copied");
SpreadsheetApp.flush();
}
}
To:
var copiedValues = [];
var putValues = [];
for(var j = 1; j < data.length;j++){
if(data[j][colToCheck-1] != "copied"){
putValues.push(data[j]);
}
copiedValues.push(["copied"]);
}
if (putValues.length > 0) { // Added
sheet.getRange(2, colToCheck, copiedValues.length, copiedValues[0].length).setValue(copiedValues);
sheetMaster.getRange(sheetMaster.getLastRow() + 1, 1, putValues.length, putValues[0].length).setValues(putValues);
}
References:
setValues(values)
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
I'm not sure about your actual Spreadsheet. So if I misunderstood your question and this was not the direction you want, I apologize.

Why does ss.deleteSheet() unhide one hidden sheet

I've written a little script that automatically deletes all Sheets my user accidentally create.
Often, when accessing the spreadsheet with their phone, they accidentally click on "+" and create tons of empty sheets, like Sheet101, Sheet102, etc.
My script is very simple: gets all sheets, and if the name starts with Sheet, just deletes it.
It works perfectly, but after deleting all the undesired sheets, the problem is that it automatically unhides the first hidden sheet (some sheets are hidden for practical use, like they contain lists).
For example, if I have the following hidden sheets:
oldform, list1, list2, ...
After executing the script, the sheet oldform will be unhidden, thus appearing to the users.
Here is two codes I've tried:
The simple one:
function DELETESHEETS2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (i = 0; i < sheets.length; i++) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
ss.deleteSheet(sheets[i]);
}
}
}
The one I tried to modify to solve my problem:
function DELETESHEETS3() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (i = 0; i < sheets.length; i++) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
label = sheets[i].getName();
toto = ss.getSheetByName(label);
ss.deleteSheet(toto);
}
}
}
The reverse loop
With this one, the hidden sheet appears at the beginning and not at the end:
function DELETESHEETS2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (i = sheets.length -1; i > 0 ; i--) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
ss.deleteSheet(sheets[i]);
}
}
}
A partial solution
This one works, thanks to #OMila. But it does not explain the weird behavior of a simple loop. Maybe I missed something?
function DELETESHEETS2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var hdnShts = [];
for (var i = 0; i < sheets.length; i++) {
if(sheets[i].isSheetHidden()) {
hdnShts.push(sheets[i].getName()); //saving all the hidden sheet names for later
}
}
for (i = 0; i < sheets.length; i++) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
ss.deleteSheet(sheets[i]);
}
}
for(var i = 0; i<hdnShts.length; i++) {
ss.getSheetByName(hdnShts[i]).hideSheet(); //just to make sure all the hiddens remain hidden
}
}
Thanks for your help if you have any idea!
PS: this problem is easy to reproduce, just create lots of sheets including one with a name other than Sheetxxx
Try this:
function delSheetsKeepHidden() {
var ss = SpreadsheetApp.getActive();
var shts = ss.getSheets();
var hdnShts = [];
for (var i = 0; i < shts.length; i++) {
if(shts[i].isSheetHidden()) {
hdnShts.push(shts[i].getName()); //saving all the hidden sheet names for later
}
}
for(var i = 0; i < shts.length; i++) {
if(shts[i].getName().slice(0,5).toLowerCase() == "sheet") {
ss.deleteSheet(shts[i]); //I think this is just deleting the sheet and not the array element in shts so no reason to keep track of deleted sheets like when deleting rows in a spreadsheet
}
}
for(var i = 0; i<hdnShts.length; i++) {
ss.getSheetByName(hdnShts[i]).hideSheet(); //just to make sure all the hiddens remain hidden
}
}
I've been forcing myself to get away from old school loops.
function delSheetsKeepHidden() {
var ss=SpreadsheetApp.getActive();
var shts=ss.getSheets();
var hdnShts=[];
shts.forEach(function(sht){if(sht.isSheetHidden()){hdnShts.push(sht.getName())}});
shts.forEach(function(sht){if(sht.getName().slice(0,5).toLowerCase()=="sheet"){ss.deleteSheet(sht);}});//I think this is just deleting the sheet and not the array element in shts so no reason to keep track of deleted sheets like when deleting rows in a spreadsheet
hdnShts.forEach(function(name){ss.getSheetByName(name).hideSheet();});//just to make sure all the hiddens remain hidden
}

Google scripts code running slow when batching functions

I use a cell to help trigger functions in a spreadsheet I made
ie: when cell A13 = "loading old orders" do this
It should run for around 4 mins then end
then it repeats this until the code finds "2015-11-09T22:40:56" in col C
I am finding that some of these calls are taking a lot longer now that the sheet is growing in size.
I am after some ideas to make the code more efficient
Thanks in advance
function getOldOrders(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var status = ss.getSheetByName('Main');
var sheet = ss.getSheetByName('Summary');
var StatusCellToWatch = status.getRange("A13");
var offset = 0;
if (StatusCellToWatch.getValue() === "Loading Old Orders") {
try {
var beforedate = sheet.getRange(sheet.getLastRow() - 1,21).getValue();
}
catch(e) {
var beforedate = "2999-03-22T19:28:02";
}
//StatusCellToWatch.setValue(beforedate);
getOrders('&before='+beforedate,offset);
StatusCellToWatch.setValue('Loading Old Orders');
//Set sheet status so that the dataset just updates and grabs new orders
var data = sheet.getRange('C30000:C').getValues();
var search = "2015-11-09T22:40:56";
for (var i=0; i < data.length; i++) {
if (data[i][0] == search) {
StatusCellToWatch.setValue('');
FormatSummary();
}
}