I have a large sheet with over 4000 rows and 30 columns.
I am trying to automaticly add new rows to the sheet if there are less than x "empty" rows. Empty rows are defined by just containing formulas but the data column A is empty.
To check if a row is empty or not I check column A, because you have to enter data in column A. After adding new rows the script should copy/paste the last row before over the new rows, so they contain the formulas as well.
Here is the script (PREVIOUS VERSION):
function addRowsItems() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('items');
var freeRows = 300; // Number of empty Rows after last Entry
var lRow = sh.getLastRow(), lCol = sh.getLastColumn(), range = sh.getRange(lRow,1,1,lCol);
var startRow = lRow-freeRows;
if(startRow < 0) {
startRow = 1; }
var values = sh.getRange("A" + startRow + ":A").getValues();
var maxIndex = values.reduce(function(maxIndex, row, index) {
return row[0] === "" ? maxIndex : index;
}, 0);
var maxIndex = maxIndex + startRow;
var space = lRow - maxIndex;
var addLines = freeRows - space;
if(space < freeRows) {
sh.insertRowsAfter(lRow, addLines);
range.copyTo(sh.getRange(lRow+1, 1, addLines, lCol), {contentsOnly:false});
}
}
This is working in a new sheet with less data.
But using it in the main sheet with over 4000 rows of data I get a time out. The script adds the new rows but it times out before it is able to copy/paste.
Why is it taking so much time? Is there an easier way to achieve that?
So this is the actual version. Cell B1 contains COUNBLANK of Range A:A.
function addRowsItems() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('items');
var freeRows = 307; // Number of empty Rows after last Entry
var lRow = sh.getMaxRows(), lCol = sh.getMaxColumns(), range = sh.getRange(lRow,1,1,lCol);
var space = sh.getRange("B1").getValues();
var addLines = freeRows - space;
if(space < freeRows) {
sh.insertRowsAfter(lRow, addLines);
range.copyTo(sh.getRange(lRow+1, 1, addLines, lCol), {contentsOnly:false});
}
}
Try the COUNTBLANK function returns a count of empty cells in a range. Cells that contain text, numbers, errors, etc. are not counted. Formulas that return empty text are counted.
Related
I have a fairly large dataset containing about 40,000 rows (New rows added daily). I want to run a script daily that deletes rows that are older than 1 year.
I have been using this one that has worked ok, but as my dataset gets larger it times out and fails to run.
here is what I have been using:
function deleteFIVEoh() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("theFIVEoh");
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();//today
var yearOld = Date.now() + -365*24*3600*1000;
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][4];// arrays are 0 indexed so row1 = values[0] and col12 =.
[11]
if ((tempDate!="") && (tempDate <= (yearOld)))
{
sheet.deleteRow(i);
}
}
}
The data on my sheet is always sorted in ascending order (oldest entries at the top). Is there any way I can get this to work faster? Maybe by looking at the first 500 rows only?
Thanks in advance!
-wes
Since your sheet is sorted in ascending order, it is much better to start at the top, count the number of rows that satisfy your condition, then use a single deleteRows() method.
function deleteFIVEoh() {
const MS_IN_ONE_YEAR = 365*24*3600*1000;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("theFIVEoh");
var datarange = sheet.getDataRange();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();//today
var yearOld = new Date(currentDate.getTime() - MS_IN_ONE_YEAR);
for (i = 0; values[i][4] < yearOld; i++) {}
sheet.deleteRows(1,i);
}
A single call is much faster than a looped API call, and there are less iterations in this code as well as it does not need to go through the entire sheet.
Sample before execution:
Sample after execution:
Basically, this is what I want to do as a custom formula for a conditional format in Google Sheets:
If any cell in range + any other cell in range = the value I specify;
Return those cells (i.e. format them as I say).
What I'm doing is, I have a column of about 80 numerical (currency) values and I'm trying to figure out if any two of them sum to a given value.
Here is a sheet where i've demonstrated the solution with this (somewhat) simple formula:
=ARRAYFORMULA(QUERY(SPLIT(TRANSPOSE(SPLIT(TEXTJOIN("#",TRUE,IF(ROW(B2:B100)<TRANSPOSE(ROW(B2:B100))*(B2:B100<>""),B2:B100&"|"&TRANSPOSE(B2:B100),)),"#")),"|"),"where Col1+Col2="&D2))
Rafa Guillermo is right. It would be much easier to do it with a script, you can try this one:
function sum() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1"); //Enter the name of your sheet.
var column = 1; //Choose the number of column you want
var startRow = 2; //Choose the number of the first row with values
var lastRow = sheet.getLastRow();
var wantedSum = 50; //Your desired value.
var values = sheet.getRange(startRow, column, lastRow-1).getValues();
for (var i = 0;i<lastRow-startRow+1;i++) {
var a = values[i][0];
for (var j = 0;j<lastRow-startRow+1;j++) {
var b = values[j][0];
if (a+b == wantedSum) {
sheet.getRange(startRow+i, column).setBackground("green"); //You can edit this to the color or format you want.
sheet.getRange(startRow+j, column).setBackground("green");
return; // This stops when it finds the first pair that sums what you want, but there may be other pairs.
}
}
}
}
Remember to edit the name of your sheet, the column, the first row with values of that column and the value you are looking for.
Ideally, I want to be able to search through an entire sheet (or range of cells) and remove any values that have been repeated in that sheet (for example, if "2" appears in A3, B8, and D4, then I want to keep it in A3 and delete it in B8 and D4).
I normally see this problem addressed by looking at one column or row for duplicates (using the UNIQUE function) but not for an entire sheet.
How can I do this?
Here's some code that will do that for an entire sheet.
Please note it will work on text and numbers and it will overwrite any formulas.
function removeDuplicates() {
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var range = sheet.getDataRange();
var values = range.getValues();
var traversedValues = [];
var rowCount = values.length;
var colCount = values[0].length;
for (var row = 0; row < rowCount; ++row) {
for (var col = 0; col < colCount; ++col) {
var value = values[row][col];
if (traversedValues.indexOf(value) > -1) {
values[row][col] = null;
} else {
traversedValues.push(value);
}
}
}
range.setValues(values);
}
References for you
Beginner's guide to coding with Google Apps Script
For loops
if...else statements
Arrays
I manage a large email list for my gaming society. In column A, I have the e-mails, and in column B, I have the usernames. I populate column B with a formula that extracts the name of the user from their e-mail address, which is often in the firstname.lastname#email.com form. Column B therefore returns "Firstname" after I run the formula if the user's email is in the firstname.lastname#email.com format.
Sometimes, however, the emails have just the initial of the first name (f.lastname#email.com) and, in these case, I want to have Column B return the word 'Gamer' rather than, for example, the first letter of the user's email.
Here is the script I use at the moment, which current deletes all rows with four or more numbers:
function removeNumbers() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (row[0].toLowerCase().indexOf("robot") > -1) {
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++;
}
On your shared spreadsheet, use this
function firstName() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var lr=sheet.getLastRow()
var val = sheet.getRange(2,1,lr-1,2).getValues();//get the col A email addrs
var newVal=[]//new array for before fitst period
for (var i = 0; i <= val.length-1; i++) {
var str=val[i][0].split(".")//split email at period
var len=str[0].length // determine lenght of number string of first split
if(val[i][1]=="inactive"){
newVal.push(["inactive"])
continue
}
if(len<=1){//if 1 or less
def="Gamer"
newVal.push([def]) //put Gamer in new array
}
else{
newVal.push([toTitleCase(str[0])]) //keep first name
}}
sheet.getRange(2, 2, newVal.length, 1).setValues(newVal)//set new values in col B
}
function toTitleCase(str) {
return str.replace(/\w\S*/g, function (txt) {
return txt.charAt(0)
.toUpperCase() + txt.substr(1)
.toLowerCase();
});
}
This well also run on the active sheet.
screenshot
Hi all, i need help and i am not a coder. I am trying to achieve the same thing on sheet number 2.
My datas are imported through "=Submission!$b2" from sheet 1
i need help removing rows automatically when a specific cell on column H does not contain the value "Bekreft", i tried both codes shown here with no success.
This is what i added for script:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('DATA - Do Not Touch!!!'); // change to your own
var values = s.getDataRange().getValues();
for(var i=values.length;i>0;i-=1){
var lcVal=values[i-1][0].toLowerCase() //Change to all lower case
var index = lcVal.indexOf("vent"); //now you only have to check for contains "vent"
if (lcVal.indexOf("vent") > -1){
s.deleteRow(i)};
}}
Seeing as you state you are "not a coder", and the code you pasted will not help you if you are referencing data from another page, I would suggest using a filter function to achieve your goal. You would add the following formula to your second page:
=FILTER(Submission!B:B,ISNUMBER(SEARCH("Bekreft", Submission!H:H)))
If you are looking to have a script go through your static list and delete out values that do not contain "Bekreft" then you can use the following script.
function onEdit() {
var sheet = SpreadsheetApp.openById("Add Sheet ID").getSheetByName('Sheet1');
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
//row for condition
if (row[7].indexOf("Bekreft")) {
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++;
}
}
};