I have put this little script together to insert an if(vlookup) formula into a spreadsheet but even though it is running it isn't inserting anything into the spreadsheet. Can anyone suggest what I have missed off or overlooked please?
Or is there an easier way to do this with an array? I'm still fairly new so not sure how I would execute that successfully.
function idSiteCoordinator(){
var SS = SpreadsheetApp.getActiveSpreadsheet();
var shLog = SS.getSheetByName("LOG");
//declare how many rows to interrogate (to the last row)
var lastRow = shLog.getLastRow();
var startRow = 2;
for (var i=startRow; i<lastRow+1; i++)
{
//Grab the values for LocationCodes
var siteCo = shLog.getRange([i],[12]).getValue();
//Enter formula
if(siteCo = ""){
siteCo.setFormula('=if(E'+[i]+'="08 - Maintenance Request System",LocationCodes!$E$33,vlookup(D'+[i]+',LocationCodes!$D$3:$E$32,2,false))');
}
}
}
You cannot apply the method setFormula to the value, but to the range. Change this on your method:
var siteCo = shLog.getRange([i],[12]);
if(siteCo.getValue() == ""){
siteCo.setFormula('=if(E'+[i]+'="08 - Maintenance Request System",LocationCodes!$E$33,vlookup(D'+[i]+',LocationCodes!$D$3:$E$32,2,false))');
}
Related
I have a code written to insert a single row into a google sheet below a keyword (a little clunky but I don't mind, unless anyone has a fix for it off the top of their head). Problem is, I want to add 250 rows beneath that and, being new to app scripts, I'm not sure where to specify the number of rows I want it adding for me.
Here's what the code I've got looks like:
function addRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var EditSheet = ss.getSheetByName("Testing"); //source sheet
var LastRowEdit = ss.getLastRow();
for(var i = 1; i <= LastRowEdit; i++)
{
if(EditSheet.getRange(i,1).getValue() == 'add') //keyword
{
EditSheet.insertRowAfter(i);
}
}
}
I would love to hear your suggestions for how I can adjust this to match my goals.
Thank you, guys!
In your situation, how about using insertRowsAfter(afterPosition, howMany) instead of insertRowAfter(afterPosition)? So, how about the following modifcation?
From:
EditSheet.insertRowAfter(i);
To:
EditSheet.insertRowsAfter(i, 250);
By the way, in your script, getValue() is used in a loop. In this case, the process cost becomes high. In order to reduce the cost, how about the following modification?
Modified script:
function addRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var EditSheet = ss.getSheetByName("Testing");
var LastRowEdit = ss.getLastRow();
var row = EditSheet.getRange("A1:A" + LastRowEdit).getValues().map(([a]) => a).indexOf("add");
if (row != -1) {
EditSheet.insertRowsAfter(row + 1, 250);
}
}
Reference:
insertRowsAfter(afterPosition, howMany)
I have around 5000 rows. Now I want to move data for one sheet to another if their status is Delivered.
This is what I am doing:
function move(){
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var lastSourceRow = sourceSheet.getLastRow();
var lastSourceCol = sourceSheet.getLastColumn();
var sourceRange = sourceSheet.getRange(1, 1, lastSourceRow, lastSourceCol);
var sourceData = sourceRange.getValues();
var activeRow = 0;
//Loop through every retrieved row from the Source
for (row = lastSourceRow; row > 1; row--) {
//IF Column B in this row has 'deal', then work on it.
if (sourceData[row-1][1] === 'Delivered') {
//then push that into the variables which holds all the new values to be returned
activeSheet.appendRow(sourceData[row-1]);
//delete current
sourceSheet.deleteRow(row);
}
Logger.log(row);
}
}
My problems:
Script is so slow it takes so much time to execute.
As per google policy script timeout in 5 mins.
So the loop has to be started again. So also index is set to null. So I can't check the record at the top if they are delivered or not.
Please can anyone provide me a better solution for this? I search for a faster loop but still no luck.
function move(){
const ash=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
const ssh=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data=ssh.getDataRange().getValues();
var d=0;
var oA=[];
data.forEach(function(r,i){
if(r[1]=="Delivered") {
oA.push(r);
ssh.deleteRow(i+1-d++);
}
});
ash.getRange(ash.getLastRow()+1,1,oA.length,oA[0].length).setValues(oA);
}
The deletion of the rows always takes time. You could splice them out of the data array and clear the sheet and place them back in with a setvalues(). But if you have formulas this may mess some things up. I'll leave that up to you.
I have a problem where I have two sheets. one sheet is the source spreadsheet and another is a target spreadsheet. The source spreadsheet has a source sheet has which is the master database and the target spreadsheet has the target where we want to fetch data from source sheet based on emails provided in the Emails tab in the target spreadsheet.
I want the following things to happen with a script and not with IMPORTRANGE or QUERY:
The target spreadsheet will have multiple copies so I want to connect the target spreadsheet with the source spreadsheet based on the source spreadsheet's id.
I want the email matches to be case insensitive so that the users of the target spreadsheet can type emails in any case.
The Emails can go up to 50 or let's say get the last row for that column.
It will be great if the script shows a pop up saying updated after it has fetched the data.
The source sheet might have data up to 15000 rows so I am thinking about speed too.
I have shared both of the spreadsheets with hyperlinks to their names. I am not really great at scripts so it will be helpful if you can leave comments in it wherever you feel like. I would truly appreciate your help.
Thanks in advance!
Script here:
function fetch() {
//get the sheets
var source_Ssheet = SpreadsheetApp.openById('19FkL3rsh5sxdujb6x00BUPvXEEhiXfAeURTeQi3YWzo');
var target_Ssheet = SpreadsheetApp.getActiveSpreadsheet();
//get the tabs
var email_sheet = target_Ssheet.getSheetByName("Emails");
var target_sheet = target_Ssheet.getSheetByName("Target Sheet");
var source_sheet = source_Ssheet.getSheetByName("Source Sheet");
//get ranges
var email_list = email_sheet.getRange("B2:B");
var target_sheet_range = target_sheet.getRange("A1:F100");
var source_sheet_range = source_sheet.getRange("A1:F100");
//get last rows
var last_email_name = email_list.getLastRow();
var last_target_sheet_range = target_sheet_range.getLastRow();
var last_source_sheet_range = source_sheet_range.getLastRow();
//start searching for emails
for (var i=3; i < last_email_name.length+1; i++)
{
for(varj=3; j< last_source_sheet_range.length+1; j++ )
{
if(source_sheet_range[j][3].getValue() == email_list[i][3].getValue())
{
//copy matches to target sheet
target_sheet.getRange((last_target_sheet_range + 1),1,1,10).setValues(master_sheet_range[j].getValues());
}
}
}
}
Several things
last_email_name and last_source_sheet_range are numbers - they do not have any length, this is why your first forloops are not working
You are missing a space in varj=3;
email_list[i][3].getValue() does not exist because email_list only includes B - that only one column. I assume you meant email_list[i][0].getValue()
ranges cannot be addressed with the indices [][], you need to retrieve the values first to have a 2D value range.
You email values in the different sheets do not follow the same case. Apps Script is case sensitive, to suee the == comparison you need to use the toLowerCase() method.
Also mind that defining getRange("B2:B") will include many empty rows that you don't need and will make your code very slow. Replace it through getRange("B2:B" + email_sheet.getLastRow());
Have a look here at the debugged code - keep in mind that there is still much room for improvement.
function fetch() {
//get the sheets
var source_Ssheet = SpreadsheetApp.openById('19FkL3rsh5sxdujb6x00BUPvXEEhiXfAeURTeQi3YWzo');
var target_Ssheet = SpreadsheetApp.getActiveSpreadsheet();
//get the tabs
var email_sheet = target_Ssheet.getSheetByName("Emails");
var target_sheet = target_Ssheet.getSheetByName("Target Sheet");
var source_sheet = source_Ssheet.getSheetByName("Source Sheet");
//get ranges
var email_list = email_sheet.getRange("B2:B" + email_sheet.getLastRow()).getValues();
var target_sheet_range = target_sheet.getRange("A1:F100").getValues();
var source_sheet_range = source_sheet.getRange("A1:F100").getValues();
var last_target_sheet_range = target_sheet.getLastRow();
//start searching for emails
for (var i=1; i < email_list.length; i++)
{
for(var j=1; j< source_sheet_range.length; j++ )
{
if(source_sheet_range[j][0].toLowerCase() == email_list[i][0].toLowerCase())
{
target_sheet.getRange((last_target_sheet_range + 1),1,1,6).setValues([source_sheet_range[j]]);
}
}
}
}
I need some help refining this code. It should copy a specific worksheet in this case the sheet Master Copy based on the rows on the sheet Maxes. Then rename the sheet to the name on the given row in the sheet Maxes. When I try to execute the code all it does is insert a blank page and adds it to the end of the Spreadsheet. Please forgive the poorly written code I am really new at this and trying to make something work. Any suggestions that you could give would be gratefully appreciated. I'm not sure if there is an error within the while loops or what exactly.
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A300");
var nameStartRow = nameSource.getRange("A2");
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("a1:m66");
var nameEndRow = nameSource.getLastRow();
var lifterName;
while (nameStartRow <= nameEndRow)
{
lifterName = nameSource.getCell(nameStartRow, nameColumn);
if (lifterName == null)
{
errors.clear();
ss.getSheetsByName(lifterName) = lifterName;
if(errors.number() > 0)
{
errors.clear();
var newSheet = ss.insertSheet();
ss.renameActiveSheet(lifterName);
ss.getSheetByName(lifterName);
trainingRange.copyValuesToRange(lifterName,1,1,16,66);
lifterName.copyValuesToRange(lifterName,4,1,4,1);
}
} nameStartRow = nameStartRow + 1;
}
}
I modifyed your code because I didn't understood what you wanted exactlly, I hope this will do the trick:
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A").getValues(); // it's a table of table [][]
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("A1:M66").getValues(); // get values give a table of table
for(var i in nameColumn){
if(nameColumn[i][0]!=""){ // if blank we skip
try{ // try to see if already exist who know...
var lifter = ss.getSheetByName(nameColumn[i][0]).activate();
Logger.log("getting lifter sheet "+nameColumn[i][0]);
}
catch(err){ // well it didn't exist so lets create it :D
var lifter = ss.insertSheet(nameColumn[i][0]);
Logger.log("creating lifter sheet "+nameColumn[i][0]);
}
SpreadsheetApp.flush();
lifter.getRange("A1:M66").setValues(trainingRange); // passing the value to the created sheet
}
}
}
I also have a demo sheet here.
Please tell me if this is what you wanted (if not can you give a demo sheet of what you want and what you should get at the end)
EDIT
here the script with formulas copy (it's not nice because you are forced to define in the script where your formulas are, we could have the script to analyse the spreadsheet to search the formulas, but, has it's a copy from template, it's less ressource consuming not to do so.)
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A").getValues(); // it's a table of table [][]
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("A1:H21").getValues(); // get values give a table of table
var trainingFormulasD = trainingSheet.getRange("D2:D21").getFormulas(); // get the formulas to copy
var trainingFormulasH = trainingSheet.getRange("H2:H21").getFormulas(); // get others formulas to copy
for(var i in nameColumn){
if(nameColumn[i][0]!=""){ // if blank we skip
try{ // try to see if already exist who know...
var lifter = ss.getSheetByName(nameColumn[i][0]).activate();
Logger.log("getting lifter sheet "+nameColumn[i][0]);
}
catch(err){ // well it didn't exist so lets create it :D
var lifter = ss.insertSheet(nameColumn[i][0]);
Logger.log("creating lifter sheet "+nameColumn[i][0]);
}
SpreadsheetApp.flush();
lifter.getRange("A1:H21").setValues(trainingRange); // passing the value to the created sheet
lifter.getRange("D2:D21").setFormulas(trainingFormulasD); //passing formulas
lifter.getRange("H2:H21").setFormulas(trainingFormulasH); //passing formulas
}
}
}
I want to create a function that will iterate over every sheet until a given sheet. The function receives the name of that last sheet as an argument.
function getUntilMonthSavings(month) {
var spreadsheet = SpreadsheetApp.getActive();
var monthSheet = spreadsheet.getSheetByName(month);
var allSheets = spreadsheet.getSheets();
var sheetNumber = monthSheet.getIndex();
var totalSavings=0;
for (var i = 1; i < monthSheet; i++){
totalSavings = totalSavings + allSheets[i].getRange("I20").getValue();
}
return totalSavings;
}
My problem is that what is returned is always 0. I've also returned i to check if it is being iterated, but it returns 1 even when the sheet index is greater than 1.
I'm sure to be doing some kind of basic blunder, but I'm quite at a loss as why this code is not working.
MonthSheet is an object and not something you can compare i to in your loop. You need the actual index of the sheet referred to.
Try:
for (var i = 0; i < monthSheet.getIndex(); i += 1) {