I need help to clean up a script that blocks rows - google-apps-script

The code below works but requires too much time to work. In fact, the script cannot finish the code, since the time to process the script has passed several times.
I gladly received help to fine-tune this code
The script was created to block (grouped) rows, if a value is entered in column E. This code is activated every 24 hours as a trigger.
Objective: The worksheet with 1000 rows, is accessible to 250 people, whether or not registered with a google account, and serves to record recreational tennis matches.
var MaxRow = Sheet.getDataRange().getNumRows();
var RowCount = 1;
var Cell = Sheet.getRange("D"+ RowCount);
var CellValue = Cell.getValue();
var BlockStart = 0;
var BlockEnd = 0;
var LockRange = Sheet.getRange(59,6,1,2);
for (RowCount = 4; RowCount <= MaxRow ; RowCount++) {
Cell = Sheet.getRange("D"+ RowCount);
CellValue = Cell.getValue();
if (CellValue != "") {
if (BlockStart == 0) {
BlockStart = RowCount;
BlockEnd = RowCount;
}
else {
BlockEnd = RowCount;
}
}
else {
if (BlockStart > 0) {
LockRange = Sheet.getRange(BlockStart,6,BlockEnd-BlockStart + 1,2);
var Protection = LockRange.protect().setDescription('Rows ' +
BlockStart + ' To ' + BlockEnd + ' Protected');
Protection.removeEditors(Protection.getEditors());
BlockStart = 0;
BlockEnd = 0;
}
}
}

Without a complete function I can't really figure out what you're trying to do. But let's say that you want to read the values in column D from line 4 to the bottom of data, then here's a simple and fast way to do it. This isn't the only way. But it's a lot faster than using getValue() on each row. This will probably run about 10000 times faster.
function getDataInColumnD() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getRange(4,4,Sheet.getLastRow()-3,1);
var vA=rg.getValues();
for (var i=0;i<vA.length;i++) {
var value=vA[i][0];
var row=i+4;
Logger.log('col: 4, row: %s, value: %s',row,value);
}
}

Related

How can Google Sheets Form Update Records from Results Using Google App script?

I have a program that filters and updates data from an existing sheet.
The program works as follows:
1. Find and filter out the required value
2. Enter data in [Adjustment] column then update to database in Record sheet.
I tried to try but my program doesn't seem to work.
I tried to edit the program code but when run it will affect the other columns and the [adjustment] column value is entered wrong.
This is my link program
function Searchold(){
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var shtRecords = ss. getSheetByName ("RECORD");
var shtForm = ss. getSheetByName ("TEST") ;
var records = shtRecords. getDataRange () . getValues ();
var sField = shtForm. getRange ("A3").getValue ();
var sValue = shtForm.getRange ("A6").getValue();
var sCol = records [0].lastIndexOf(sField);
var results = records.filter(function(e){return sValue == e[sCol] });
if(results.length==0){SpreadsheetApp.getUi().alert("not found values");}
else{
shtForm.getRange(9,1,results.length,results[0].length).setValues(results);
}
}
function Updatenew(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var shtRecords = ss.getSheetByName("RECORD");
var shtForm = ss.getSheetByName("TEST");
var LastRow = shtForm.getRange("A8").getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow();
var newData = shtForm.getRange(9,1,LastRow -1,7).getValues();
for(var i =0; i<newData.length;i++){
var oldData= shtRecords.getDataRange().getValues();
for(var j= 0;j<oldData.length;j++){
if(newData[i][0] ==oldData[j][0]){
var newData2 = [newData[i]];
shtRecords.getRange(j + 1,1,1,newData2[0].length).setValues(newData2);
}
}
}
}
Can you help me with the update program? Sincerely thank you
Modification points:
When I saw your showing script of Updatenew, I think that each row of var oldData = shtRecords.getDataRange().getValues() is used in each loop of for (var i = 0; i < newData.length; i++) {}. By this, each row is overwritten by each row of newData. By this, all searched rows in "RECORD" sheet are the same value. I thought that this might be the reason for your issue.
var oldData = shtRecords.getDataRange().getValues(); can be used one call.
In order to avoid this issue by modifying your script, as one of several methods, how about the following modification?
From:
for (var i = 0; i < newData.length; i++) {
var oldData = shtRecords.getDataRange().getValues();
for (var j = 0; j < oldData.length; j++) {
if (newData[i][0] == oldData[j][0]) {
var newData2 = [newData[i]];
shtRecords.getRange(j + 1, 1, 1, newData2[0].length).setValues(newData2);
}
}
}
To:
var oldData = shtRecords.getDataRange().getValues();
for (var j = 0; j < oldData.length; j++) {
for (var i = 0; i < newData.length; i++) {
if (newData[0][0] == oldData[j][0]) {
var newData2 = newData.splice(0, 1);
shtRecords.getRange(j + 1, 1, 1, newData2[0].length).setValues(newData2);
break;
}
}
}
Note:
At the above modification, setValues is used in a loop. In this case, the process cost becomes high. If you want to reduce the process cost of the script, how about using Sheets API? When Sheets API is used, how about the following modification? Please enable Sheets API at Advanced Google services.
To
var temp = newData.slice();
var data = shtRecords.getDataRange().getValues().reduce((ar, r, i) => {
if (temp[0][0] == r[0]) {
var t = temp.splice(0, 1);
t[0][2] = Utilities.formatDate(t[0][2], Session.getScriptTimeZone(), "dd/MM/yyyy");
t[0][4] = Utilities.formatDate(t[0][4], Session.getScriptTimeZone(), "dd/MM/yyyy");
ar.push({ range: `'RECORD'!A${i + 1}`, values: t });
}
return ar;
}, []);
Sheets.Spreadsheets.Values.batchUpdate({ data, valueInputOption: "USER_ENTERED" }, ss.getId());

Speed up apps script from MySQL Query Google Sseets

I am facing an issue like many before with regards to a timeout out Google Apps Script, I am reading the data from a indexed/persisted table in a MySQL Database, the table in question has 71 columns and a total of 28000 rows, the sheet in google sheets I am writing to has no calculations etc on it which might slow things down - those happen on other sheets.
Please can you review the below that I am using and propose any changes to assist in avoiding the time out?
var server = 'xx.xx.xx.xxx';
var port = xxxx;
var dbName = 'test';
var username = 'test';
var password = 'xxx';
var url = 'jdbc:mysql://'+server+':'+port+'/'+dbName;
function readDataPast() {
var conn = Jdbc.getConnection(url, username, password);
var stmt = conn.createStatement();
var results = stmt.executeQuery('SELECT * FROM test.test_table');
var metaData = results.getMetaData();
var numCols = metaData.getColumnCount();
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName('Raw_Data');
sheet.clearContents();
var arr = [];
let row = [];
for (var col = 0; col < numCols; col++) {
row.push(metaData.getColumnName(col + 1));
}
arr.push(row);
while (results.next()) {
row = [];
for (var col = 0; col < numCols; col++) {
row.push(results.getString(col + 1));
}
arr.push(row)
}
sheet.getRange(1, 1, arr.length, arr[0].length).setValues(arr);
results.close();
stmt.close();
}
Issue:
I don't think the script can be made considerably faster, since potential improvements (e.g. using Sheets API as suggested by Ninca Tirtil) don't affect significatively the bulk of the script (iterating through 28000 rows).
Workaround:
Therefore, instead of trying to speed it up, I'd suggest accomplishing this in multiple executions. To that goal, I'd do the following:
Check execution time after each iteration. If this time is close to the time limit, end the loop and write current data to the sheet. You can use the Date object for this.
Create the following time-based trigger at the end of your function: after(durationMilliseconds). Thanks to this, the function will fire automatically after the amount of milliseconds you indicate. After each execution, a trigger will be created to fire the next execution.
Because you want to split the loop, you have to store the row index somewhere (you could use PropertiesService at the end of each execution, for example) and retrieve it at the beginning of the next, so that in each successive execution, the script resumes the loop where it left it. You can get the row index via getRow(), and then move to that row in the next execution via relative(rows).
Code sample:
var maxTimeDiff = 1000 * 60 * 5; // 5 minutes
const PROPERTY_KEY = "Row index";
function setRowIndex(rowIndex) {
const scriptProps = PropertiesService.getScriptProperties();
scriptProps.setProperty(PROPERTY_KEY, rowIndex);
}
function getRowIndex() {
const scriptProps = PropertiesService.getScriptProperties();
const rowIndex = scriptProps.getProperty(PROPERTY_KEY);
return rowIndex;
}
function createTrigger() {
ScriptApp.newTrigger("readDataPast")
.timeBased()
.after(60 * 1000) // Next execution after a minute
.create();
}
function readDataPast() {
var startTime = new Date();
var conn = Jdbc.getConnection(url, username, password);
var stmt = conn.createStatement();
var results = stmt.executeQuery('SELECT * FROM test.test_table');
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName('Raw_Data');
var rowIndex = getRowIndex();
var arr = [];
let row = [];
if (!rowIndex || rowIndex == 0) { // Clear sheet and add metadata if first execution
sheet.clearContents();
var metaData = results.getMetaData();
var numCols = metaData.getColumnCount();
for (var col = 0; col < numCols; col++) {
row.push(metaData.getColumnName(col + 1));
}
arr.push(row);
} else {
results.relative(rowIndex); // Move to current row
}
while (results.next()) {
row = [];
for (var col = 0; col < numCols; col++) {
row.push(results.getString(col + 1));
}
arr.push(row);
if (new Date() - startTime > maxTimeDiff) break; // End iteration if long time
}
var currentRow = results.getRow(); // 0 if all rows have been iterated
setRowIndex(currentRow);
var lastRow = sheet.getLastRow();
sheet.getRange(lastRow + 1, 1, arr.length, arr[0].length).setValues(arr);
results.close();
stmt.close();
if (currentRow) createTrigger(); // Create trigger if iteration is not finished
}

Reduce script execution time - Google script

I made a script that works properly (does what I want it to), however, it's painfully slow and at this pace, it will finish in about 20 days. I can't wait for 20 days and I'm not good enough at this to make it faster on my own.
Here's a brief description of the task:
Masterlist - it's a sheet with 23 columns and 29000+ rows.
Seed - it's an empty sheet that I'm to copy the Masterlist to.
Duplicates - it's an empty sheet where I will store any duplicate rows.
The process:
Get the first line from Masterlist. Check if line already in Seed. If line not in Seed, add line. If line already in Seed, add line to Duplicates. Either way, delete the original line from the Masterlist.
The definition of duplicate:
Each line has an emails column. Column can be either a single email address, or multiple email addresses separated by "; ". If an email is found within line in Masterlist and already exists within line in Seed, this whole line is considered a duplicate.
Example:
"aaa#gmail.com" is not a duplicate of "a#gmail.com; aa#gmail.com"
"bbb#gmail.com" is a duplicate of "b#gmail.com; bbb#gmail.com"
Furthermore, if the emails cell is empty in the Masterlist, this is not considered a duplicate.
Here comes my code - it works but is not fast enough.
function getSheet(name){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
return sheet;
}
function getRowByID(sheet, rowID) {
var range = sheet.getRange(rowID, 1, 1, 23);
var value = range.getValues();
return [range, value];
}
//main executes the entire thing
function main(){
var sourceSheet = getSheet('Masterlist');
var targetSheet = getSheet('Seed');
var remainingSheet = getSheet('Duplicates');
var counter = sourceSheet.getLastRow();
var start = new Date();
while(counter >= 2){
var sourceLine = getRowByID(sourceSheet, 2)[1];
var duplicates = checkEmailMatch(sourceLine, targetSheet);
if(duplicates == 0){
targetSheet.appendRow(sourceLine[0]);
sourceSheet.deleteRow(2);
}
else{
remainingSheet.appendRow(sourceLine[0]);
sourceSheet.deleteRow(2);
}
counter--;
}
}
//iterates through existing lines in the Seed sheet (locates the email cell and reads its contents)
function checkEmailMatch(row, seed){
var sourceEmail = row[0][7];
var counter = seed.getLastRow();
var result = [];
if(!counter){
return 0;
}
else{
var j = 0;
var i = 2;
for(i; i <= counter; i++){
var seedLine = getRowByID(seed, i)[1];
var seedEmail = seedLine[0][7];
if(!seedEmail){}
else if(compareEmails(seedEmail, sourceEmail) == true) {
result[j] = i;
j++;
}
}
return result;
}
}
//Compares each email in Masterlist ("; " separated) with each email in Source ("; " separated)
function compareEmails(emailSeedCell, emailSourceCell){
var seedEmails = emailSeedCell.split("; ");
var sourceEmails = emailSourceCell.split("; ");
for(var i = 0; i < seedEmails.length; i++){
for(var j = 0; j < sourceEmails.length; j++){
if(seedEmails[i] == sourceEmails[j]) return true;
}
}
return false;
}
Please help me - if you need any additional info, I'd be happy to provide! Please note that this is my third script ever, so any feedback is welcome!
Thanks to everyone who chipped in to help, I managed to come up with this code that reduced the execution time more than 10000 times! Thanks, everyone - here's the code:
function sheetToArray(name){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
var counter = sheet.getLastRow();
var columns = sheet.getLastColumn();
var array = sheet.getRange(2, 1, counter, columns).getValues();
return array;
}
function compareEmails(emailSeedCell, emailSourceCell){
var seedEmails = emailSeedCell.split("; ");
var sourceEmails = emailSourceCell.split("; ");
var result = false;
for(var i = 0; i < seedEmails.length; i++){
for(var j = 0; j < sourceEmails.length; j++){
if(seedEmails[i] == sourceEmails[j]) result = true;
}
}
return result;
}
function save2DArrayToSpreadsheet(name, array){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
sheet.getRange(2, 1, array.length, array[0].length).setValues(array);
}
function main(){
var masterArray = sheetToArray('Masterlist');
var seedArray = [];
var duplicateArray = [];
for(var i = 0; i < masterArray.length; i++){
Logger.log(i);
if(!seedArray.length){
seedArray.push(masterArray[i]);
}
else if(!masterArray[i][7]){
seedArray.push(masterArray[i]);
}
else{
var result = false;
for(var j = 0; j < seedArray.length; j++){
if(compareEmails(seedArray[j][7], masterArray[i][7]) == true){
result = true;
}
}
if(result == true){
duplicateArray.push(masterArray[i]);
}
else{
seedArray.push(masterArray[i]);
}
}
}
save2DArrayToSpreadsheet("Seed", seedArray);
save2DArrayToSpreadsheet("Duplicates", duplicateArray);
}

script slow down with more than 1 user

I have a sheet with ~18k rows in. I have written a script to divide the number of rows by the number of users who want to get involved in calculating values in the rows in the sheet and then allocating those rows to those users. A collaborative effort to speed things up as each row takes approximately 1s and it takes ~ 6-9 hours to go through it on my own with network issues etc.
When a user opens the sheet, they are allocated a user number and a chunk of rows to work on with 5 users 18k rows breaks down to 3600 rows each.
The issue is that when more than 1 or 2 users are working on the sheet, the performance becomes erratic. Sometimes a row takes 15-20s to be processed. I am saving nothing by having friends share the task.
I read somewhere that only 100 users can work on a sheet at the same time but here I am talking about 5 (up to a maximum of maybe 10 or 11) people working on the sheet, each running maybe 5-8 functions each on a trigger. Right now I have 5 users connected to the sheet, each running 8 functions and the work has slowed almost to a stop.
Does anyone have any experience with this and know of any limits google place on accounts working on a script? Any way to work with apps script to make this work properly?
Thanks for your insights!
Chad
/*NEW CODE WITH TRIGGER - WE START IT UP WITH A CALL TO runTriggersTwoTimes()*/
function runTriggersTwoTimes() {
createSplitWorkTrigger();
ScriptApp.newTrigger('createSplitWorkTrigger')
.timeBased()
.after(80 * 60 * 1000)
.create();
}
function createSplitWorkTrigger() {
ScriptApp.newTrigger('splitWork2')
.timeBased()
.everyMinutes(5)
.create();
ScriptApp.newTrigger('deleteAllTriggers')
.timeBased()
.after(60 * 60 * 1000)
.create();
}
/*This function splits the work of getting the "From" prices between multiple accounts*/
function splitWork2() {
var accountsArray = [user1, user2, user3, user4, user5#gmail.com];
var numberAccounts = accountsArray.length;
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName("CK Formatted");
var RANGE = sheet.getDataRange();
var rangeVals = RANGE.getValues();
var numberRows = rangeVals.length;
var totalChunkSize = Math.floor(numberRows / numberAccounts);
var userName = Session.getActiveUser().getEmail();
var userNumber;
for (i = 0; i < numberAccounts; i++) {
if (userName == accountsArray[i]) {
userNumber = i;
}
}
var usersStartRow = userNumber * totalChunkSize + 1
var usersLastRow = usersStartRow + totalChunkSize - 1;
if (userName == accountsArray[numberAccounts - 1]) {
usersLastRow = numberRows;
}
// This one does the main work
findFromPricesByChunks2(userNumber, usersStartRow, usersLastRow, 110, totalChunkSize);
}
/*This function adds the "From" prices in chunks*/
function findFromPricesByChunks2(userNumber, startRow, lastRow, chunkSize, totalChunkSize, checkingRound = false) {
if (startRow >= lastRow) {
var allTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < allTriggers.length; i++) {
ScriptApp.deleteTrigger(allTriggers[i]);
}
return;
}
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName("CK Formatted");
var RANGE = sheet.getDataRange();
var rangeVals = RANGE.getValues();
Logger.log(rangeVals.length);
var addedPrices = 0;
for (var i = startRow; i <= lastRow; i++) {
if (addedPrices == chunkSize) {
return;
}
var cellValue = sheet.getRange(`A${i + 1}`).getValue();
Logger.log('Cell Value:' + cellValue);
if (cellValue == '') {
Utilities.sleep(1000);
var html = UrlFetchApp.fetch(URL).getContentText();
var $ = Cheerio.load(html);
var s = $('#table .price-container .font-weight-bold').first().text();
// if we fail to get a value because of network issues or whatever this next piece is going ahead and putting a full stop in what should be an empty box. WIll think about this
if (s) {
s = s.replace(".", ",");
s = s.substring(0, s.lastIndexOf(',')) + '.' + s.substring(s.lastIndexOf(',') + 1);
}
fromArrayCell = sheet.getRange(`A${i + 1}`);
fromArrayCell.setValue(s);
addedPrices++;
}
}
var sheetCk = spreadsheet.getSheetByName("CK");
// This adds the amount of processed items to the processed rows counter (because now there are multiple workers working
// at the same time)
if (!checkingRound) {
sheetCk.getRange(userNumber + 2, 9).setValue(sheetCk.getRange(userNumber + 2, 9).getValue() + addedPrices);
} else {
sheetCk.getRange(userNumber + 2, 10).setValue(sheetCk.getRange(userNumber + 2, 10).getValue() + addedPrices);
}
}
function deleteAllTriggers() {
var allTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < allTriggers.length; i++) {
ScriptApp.deleteTrigger(allTriggers[i]);
}
}
The single most important thing to come out of this post was the limit of 30 executions which I was told before I posted any code :p I didn't know about that and it was the crux of the problem I was having. Bear in mind that the original code (a few versions back) was trying to cram 13 users in with 8 processes each :)
After drifting for a few days I had a good sleep and came up with this new improved version of the above:
function splitWork() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetCk = spreadsheet.getSheetByName("CK");
var sheet = spreadsheet.getSheetByName("CK Formatted");
var RANGE = sheet.getDataRange();
var rangeVals = RANGE.getValues();
var userName = Session.getActiveUser().getEmail();
Logger.log(userName)
var accountsArray = [gmail1, gmail2, gmail3, gmail4, gmail5];
var numberRows = rangeVals.length;
var numberAccounts = accountsArray.length;
var totalChunkSize = Math.floor(numberRows / numberAccounts);
var userNumber;
for (i = 0; i < numberAccounts; i++) {
if (userName == accountsArray[i]) {
userNumber = i;
}
}
var usersStartRow = (userNumber * totalChunkSize) + 1; // = 1
var usersLastRow = usersStartRow + totalChunkSize - 1; // = 211
if(userName == accountsArray[numberAccounts - 1]) { usersLastRow = numberRows; }
var completeRowsOriginal = sheetCk.getRange(userNumber + 2, 9).getValue() // = 109
usersStartRow = usersStartRow + completeRowsOriginal // = 110
for (var i = usersStartRow; i <= usersLastRow; i++) { // 110 - 211
var cellValue = sheet.getRange(`A${i + 1}`).getValue();
var completeRows = 0
if (cellValue == '') {
Utilities.sleep(1000);
var html = UrlFetchApp.fetch(URL).getContentText();
var $ = Cheerio.load(html);
var fromArrayCell = sheet.getRange(`A${i + 1}`);
if(sheetCk.getRange(userNumber + 2, 10).getValue() != 1){
var s = $('#table .price-container .font-weight-bold').first().text();
}
else if(sheetCk.getRange(userNumber + 2, 10).getValue() == 1) {
var s = $('#table .price-container .font-weight-bold').first().text();
if(!s) {
var s = $('#tabContent-info .info-list-container dd:nth-child(12)').text();
if(s) { fromArrayCell.setBackground('#ff8680'); }
}
}
if (s) {
s = s.replace(".", ",");
s = s.substring(0, s.lastIndexOf(',')) + '.' + s.substring(s.lastIndexOf(',') + 1);
}
fromArrayCell.setValue(s);
completeRows++
sheetCk.getRange(userNumber + 2, 9).setValue(sheetCk.getRange(userNumber + 2, 9).getValue() + 1)
}
if(completeRows >= 100 || usersStartRow + completeRows >= usersLastRow) {break}
}
if(sheetCk.getRange(userNumber + 2, 9).getValue() + usersStartRow >= usersLastRow) {
if(sheetCk.getRange(userNumber + 2, 10).getValue() != 1) {
sheetCk.getRange(userNumber + 2, 9).setValue(0)
sheetCk.getRange(userNumber + 2, 10).setValue(1)
}
}
else { deleteAllTriggers() }
}
Which works like a charm.
A user opens the sheet, is allocated a chunk in the background, presses a button to start a trigger to work on their chunk every 5 minutes and if they are feeling frisky they can run the function above while waiting for the trigger to start (also from a button). They'll scrape values for 100 rows then wait for another trigger. After they have gone through their whole chunk their counter resets and their master counter is set to 1. They then make a second pass over their chunk filling in any gaps due to network errors. If they can't get a value from the regular place on the second pass they can get a value from another place but it is marked with a red background as it is not reliable.
Don't think there is anything else left to say about this one. Try it yourselves if you have a large sheet of data to churn through and want to do it in less time with help from your friends with google accounts.
PS: CK is the sheet which is used to hold counters only
PPS!! If you literally do it as above, you will manage to process about 1 row per second. The real power coms from getting all the helper account to make their own copy of the main sheet and work on that. Here we'd get 13 rows per second processed, for instance. Then it's a simple matter to recombine everything into single sheet when they're done.

Google Sheets Script to Fill Down intermittent blanks in a column

Column C has an ID in it that pertains to several rows, but only the first row has an ID in it.
I need to copy that ID value to the blank cells beneath, until I hit a cell that has another value in it.
I have tried adapting this script but it hits a timeout error.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var last = sheet.getLastRow();//how many times should I do this?
for (i = 5528; i < last; i++) {
var test = sheet.getRange(i, 1,1,1);
//Logger.log(test);
//looks to see if the cell is empty
if (test.isBlank()) {
var rewind = sheet.getRange(i-1, 1, 1, 1).getValues();//gets values from the row above
sheet.getRange(i, 1, 1, 1).setValues(rewind);//sets the current range to the row above
}
}
}
i is set to a big number because every time it times out I have to start over!
I have read that it would be better to bring in the column in an array, work on it, then put it back out to save a lot of time.
I have tried to adapt this but can't get past the variable.
Am I on the right track? I would like to pretty up a solution for the future where I can pass a column or range and do the same thing.
Here is my failing attempt:
function FillDown2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var tracts = sheet.getRange("C15:C").getValues();
var allTractList = [];
var title;
for (var row = 0, var len = tracts.length; row < len; row++) {
if (tracts[row][0] != '') {
//response = UrlFetchApp.fetch(tracts[row]);
//doc = Xml.parse(response.getContentText(),true);
title = tracts[row][0];
//newValues.push([title]);
allTractList.push([title]);
Logger.log(title);
} else allTractList.push([title]);
}
//Logger.log('newValues ' + newValues);
Logger.log('allTractList ' + allTractList);
// SET NEW COLUMN VALUES ALL AT ONCE!
sheet.getRange("B15").offset(0, 0, allTractList.length).setValues(allTractList);
return allTractList;
}
Holy Smokes! I did it!
Not sure about why error happened but I had made some changes and got it to work!
Hope this is helpful to others:
function FillDown2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var tracts = sheet.getRange("C15:C").getValues();
var allTractList = [];
var title;
var len = tracts.length;
for (var row = 0; row < len; row++) {
if (tracts[row] != '') {
//response = UrlFetchApp.fetch(tracts[row]);
//doc = Xml.parse(response.getContentText(),true);
title = tracts[row];
//newValues.push([title]);
allTractList.push([title]);
Logger.log(title);
} else allTractList.push([title]);
}
//Logger.log('newValues ' + newValues);
Logger.log('allTractList ' + allTractList);
// SET NEW COLUMN VALUES ALL AT ONCE!
sheet.getRange("B15").offset(0, 0, allTractList.length).setValues(allTractList);
return allTractList;
}
Credit to Bryan here: