I'm attempting to write a script that will change the status (Current vs Expired) in an adjacent cell when looping over the cell values of a column containing dates if the date is equal to or less than today's date. The script needs to work on column N (dates) and modify column O (statuses) across ALL sheets in the spreadsheet. That is why I have the Sheets loop in there FYI.
Here is what I have so far and I just keep hitting walls.
It's currently throwing an error at the currentValue variable for being out of range.
//----------------------------------------------------
// Look at Dates and Change Status if expired (Automatically)
function checkDates() {
//For each sheet in the Spreadsheet
for(v in sheets){
//Find the last row that has content *-2 is because of a strange return I don't understand yet
var lastRow = sheets[v].getLastRow()-2;
//Get Dates Range (excluding empty cells)
var dateRange = sheets[v].getRange("N2:N"+lastRow);
//Get the number of Rows in the range
var numRows = dateRange.getNumRows();
//For loop for the number of rows with content
for(x = 0; x <= numRows; ++x){
// Value of cell in loop
var currentValue = dateRange.getCell(x,2).getValue();
Logger.log(currentValue);
// Row number in Range
var currentRow = dateRange.getRow(x);
// Get adjacent cell Range
var adjacentCell = sheets[v].getRange(currentRow,15);
// If the date is less than or equal to today
if(new Date(currentValue) <= d){
// Change adjancet cell to Expired
adjacentCell.setValue("Expired");
// Else adjance cell is Current
} else if(listofDates != ""){
adjacentCell.setValue("Current");
}
}
}
}
//-----------------------------------------------------
The reason for currentValue to be out of range is that the getCell(x, 2) function first parameter is the row number. Your row number starts at 0, x = 0. If you change x to start at 1 it should stop giving you the error that the currentValue variable is out of range.
for(x = 1; x <= numRows; ++x){ ...
You are also selecting 2 columns across but you only selected out of row "N", change getCell(x, 2) to getCell(x, 1).
var currentValue = dateRange.getCell(x,1).getValue();
As I mentioned before your data range is only over colmn "N", it can make it easier if you select both column "N" and "O", var dateRange = sheets[v].getRange("N2:O");
I modified the rest of your script a bit. It is not pretty but I do hope it helps you.
function checkDates() {
//For each sheet in the Spreadsheet
for(v in sheets){
var lastRow = sheets[v].getLastRow();
//Get Dates Range (excluding empty cells)
var dateRange = sheets[v].getRange(2, 14, (lastRow - 1), 2);
//Get the number of Rows in the range
var numRows = dateRange.getNumRows();
//For loop for the number of rows with content
for(x = 1; x <= numRows; ++x){
// Value of cell in loop
var currentValue = dateRange.getCell(x,1).getValue();
var adjacentCell = dateRange.getCell(x,2);
Logger.log(currentValue);
// If the date is less than or equal to today
if(new Date(currentValue) <= new Date()){
// Change adjancet cell to Expired
adjacentCell.setValue("Expired");
// Else adjance cell is Current
} else if(currentValue != ""){
adjacentCell.setValue("Current");
}
}
}
}
Related
I have a script that I need to improve. The script goes through all the rows on column A. Then, it inserts a value on the next cell based on value. For example: If the value on cell A2 is 4,9, then it will insert UNDER10 to the cell B2. It works. But, it works so slowly. If I have thousands of rows on column A sometimes the script times out. Does anybody know a way to make this script faster?
Below is my script:
function myFunction() {
const ss = SpreadsheetApp.getActive().getActiveSheet()
const lastRow = ss.getLastRow();
for (var i = 1; i < lastRow +1; i++) {
var value = ss.getRange(i,1).getValue();
var newValue = ss.getRange(i,2);
if (value < 10) {
newValue.setValue("UNDER10");
} else if (value < 20) {
newValue.setValue("UNDER20");
} else if (value > 20) {
newValue.setValue("OVER20");
}
}
}
This improvement should work. Note that I assumed column A include numbers (google sheet refer 4,9 as string. therefor, the statement if(value < 10) is not realy valid).
To test my code, I used 4.9, 14.9, etc.
function myFunction() {
const ss = SpreadsheetApp.getActive().getActiveSheet()
const lastRow = ss.getLastRow();
// get all the range at once
let range = ss.getRange(2, 1, lastRow -1, 2);
// get all the values in 2D array
let values = range.getValues();
// for each pair of values [price, custom value], calculate the custom value
values.forEach((value)=> {
// NOTE that i parse float out of price.
// Google sheet refer 4,9 as string (i assume you ment 4.9)
value[0] = parseFloat(value[0])
if (value[0] < 10) {
value[1] = "UNDER10"
} else if (value[0] < 20) {
value[1] = "UNDER20";
} else if (value[0] > 20) {
value[1] = "OVER20";
}
})
// set the new values into the spreadsheet
range.setValues(values)
}
If you ment to compare each number in each row (for example, in 'A2' cell: if(4 < 10 && 9 < 10)) please comment and I'll fix accordingly.
I think this one is pretty simple, but I am new to this, so I am not sure where to go from here :)
I have a Google Sheet, with some data (pretty large sheet). I want a script that check whether the number in a cell (column I) is larger than the number in the same row, but another column (column D).
Imagine two columns with 5 rows: Column D = (3, 3, 3, 3, 3) and Column I = (2, 2, 7, 2, 2)
SO in this example, I want that the script to tell me that I have problem in "Row 3", because the number in Column I, Row 3 is larger than the number in Column D, Row 3 :)
This is what I have:
function Check() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var lr = sheet.getLastRow();
var Summary;
for (var i=6; i<lr; i++) {
if (sheet.getRange(i,9) > sheet.getRange(i,4)){
summary.setvalue("Problem")
}
}
}
I want it to start in row 6, because my data starts here. I am only checking column I (therefore 9) and column D (therefore 4)
I am not sure what to do with my for loop and If statement from here? SO now the code is checking every row in column 4 (D) and column I (9), but how do I store store the value, whenever the number in column 9 is larger than the number in column 4? And I also want an output, with all rows where we have a problem, when the code is done? If we don't have any problem, I want a message saying: "no problem"
Can anybody guide me from here?
If your output can be set in the sheet (let say in column "J"), you can use this:
function Check() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var maxRows = sheet.getMaxRows(); // get the number of rows
var startRow = 6;
var diffCol1 = 'D';
var diffCol2 = 'I';
var outputCol = 'J';
var outputStrOK = 'no problem';
var outputStrKO = 'problem';
var outputRange = []; // stored values
for (var i = startRow; i <= maxRows; i++) {
var valueA = sheet.getRange(diffCol2+i).getValue();
var valueB = sheet.getRange(diffCol1+i).getValue();
// add controls on values then
if (valueA > valueB) {
outputRange.push([outputStrKO]);
} else {
outputRange.push([outputStrOK]);
}
}
// setting a range of values is much faster than fulfilling cell by cell in loop
sheet.getRange(outputCol+startRow+':'+outputCol+maxRows).setValues(outputRange);
}
you should have this as a result:
#|D|I|J
6|9|4|problem
7|4|9|no problem
The following script should change cell values in column K based on values in column D. However, the comparator is not working, it always returns "NO".
Is range.toString the correct syntax? I think I'm not comparing Apples to Apples.
function Test1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("report");
var numRows = SpreadsheetApp.getActiveSheet().getLastRow();
var range;
/* Loop through Column D and find cells equal to order payment
and set Column K value based on it */
for (var i = 1; i <= numRows; i++) {
range = s.getRange('D' + i );
if (range.toString() == "Order Payment") {
range.offset(0, 6).setValue("YES");
}
else {
range.offset(0,6).setValue("NO");
}
}
}
range.getValue() == "Order Payment" is the correct syntax instead of range.toString()
I have a range of dates in plain text format (must stay this way) and I need to clear them at 1am if the date in each range cell is less than the current date. I can set up the run schedule later, but can anyone tell me why this isn't working?
I'm using =TEXT(TODAY(),"m/dd") to insert the current date in the correct format in cell AE3.
Thank you!
function clearOldDate()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Loads");
var cells = sheet.getRange('AC9:AE33').getValues();
var data = [cells];
var date = sheet.getRange('AE3').getValues();
//var Sdate = Utilities.formatDate(date,'GMT+0900','MM/dd');
for(i=0; i<76; i++)
{
if (date > data[i])
{
data[i].clear();
};
};
};
This should do the trick
function clearOldDate()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("LogSheet");
//getValues gives a 2D array.
var data = sheet.getRange('AC9:AE33').getValues();
var date = sheet.getRange('AE3').getValues();
//var Sdate = Utilities.formatDate(date,'GMT+0900','MM/dd');
//This for loop with loop through each row
for(i=0; i<data.length; i++)
{
//This for loop with loop through each column
for (var j = 0; j < data[i].length ; j ++){
//This assumes Column AC has the dates you are comparing aganist
if (date > data[i][j])
{
//sets that the Row with index i to empty
data[i] = ["","",""]
};
}
};
//finally set the value back into sheet
sheet.getRange('AC9:AE33').setValues(data)
};
Basically, you need to setValues once data array is modified.
Note: This Statement (date > data[i][0]) doesn't work as expected when the values are stored as text.
Edit: Modified the code and added a new for loop to go through each column, based on comments
Context: I'm making a script for Sheets that will colour an internal Sheets calendar to show start and end dates based on filling in a task's details elsewhere in the Sheet.
Bizarre situation: For each increasing column I set the start date from, colCount is incremented an extra time (more than I want), as shown in the pictures attached. The colCount keeps track of how many cells should be painted blue (finishing at the cell before end date)
http://i.imgur.com/2kNGTIG.png - Sheet 1 with task details
http://i.imgur.com/KhNBi4Q.png - Sheet 2 with calendar, showing where the painting occurs
Why is colCount being incremented too many times?
for (var k = 2; k < 100; k++){ //iterate over rows (searching tasks)
if (ss2.getRange(k, 1).getValue() === task){ //check correct row for task
var colCount = 1;
var start;
for (var i = 2; i < 100; i++){ //iterate over columns (searching dates)
var dateCell = ss2.getRange(1, i).getValue().getTime(); //this is cell that has date
if (dateCell == startDate){
start = i; //set column where start date is
}
else if (dateCell != endDate && dateCell != startDate){
colCount++;
}
else if (dateCell == endDate){
e.range.setNote("4.5: - start " + start + " - colCount " + colCount);
ss2.getRange(k, start, 1, colCount).setBackground("#4d79ff"); //set blue
ss2.getRange(k, i).setBackground("#fe4343"); //set red, working fine
return;
}
}
}
}
Edit: found an alternative way of achieving what I wanted. I just used the line
var cols = ss2.getRange(1, i).getColumn() - start;
to get the number of columns to paint, then use cols instead of colCount.
I think your problem might be in the line
var dateCell = ss2.getRange(1, i).getValue().getTime();
Shouldn't you be getting the range (k,i) since you're on row k?