I found this code from https://stackoverflow.com/users/6656050/jeremy-kahan and edited it a little. I need my sheet to delete any row when the entry in column L is older than one month, but keep the row if the cell in column L is empty i'll need some guidance. On request I can provide a copy of my sheet and show examples. It might seem easy it others but I feel at a disadvantage only being 16 and just learning java.
function DeleteOldEntries() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");//assumes Sheet 1 is the name of the sheet
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 monthOld = Date.now() + -30*24*3600*1000;
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][11];// arrays are 0 indexed so row1 = values[0] and col12 = [11]
if (tempDate <= (monthOld))
{
sheet.deleteRow(i);
}
}
I'm going to provide some help, even though I'm going to get chastised for it. In the future, do some research, try to understand the code and make the code work for your purpose. If you can't, and Google doesn't help, THEN come on and ask a CLEAR question with all of the details. Most of the top dogs on here won't even look at your question if all of that isn't done. Also, be sure to use the correct tags on your questions. It won't even show up to the correct people without them.
Now to your answer:
You want to delete a row if the date in column L is > 30 days in the past. The code you provided is looking at column C for the date. So that is the first thing that needs to be changed. Second, the conditional if ((tempDate!=NaN) && (tempDate <= currentDate)) is checking to see if the cell is empty (NaN), or if the date is <= TODAY, NOT today - 30. So, you need a way to calculate what today - 30 days is: var monthOld = Date.now() + -30*24*3600*1000;, then you can compare that to the date in column L.
If you make those two changes, you get:
function DeleteOldEntries() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Live Events");//assumes Live Events is the name of the sheet
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 monthOld = Date.now() + -30*24*3600*1000;
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][11];// arrays are 0 indexed so row1 =
values[0] and col12 = [11]
if ((tempDate!=NaN) && (tempDate <= (monthOld)))
{
sheet.deleteRow(i);
}
}
}
This should do what you want. If you have any further questions, let me know. I'm happy to help.
function DeleteOldEntries() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");//assumes Sheet 1 is the name of the sheet
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 monthOld = Date.now() + -30*24*3600*1000; //to change amount of days adjust "30"
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][11];// arrays are 0 indexed so row1 = values[0] and col12 = [11]
if ((tempDate!="") && (tempDate <= (monthOld)))
{
sheet.deleteRow(i);
}
}
}
Related
I'm breaking my head here trying to figure it out a way to achieve this in a simples way.
I got working a code that copies a range from a sheet and paste in another at the last row.
function copyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Review");
var pasteSheet = ss.getSheetByName("Log");
// get source range
var source = copySheet.getRange(3,2,15,5);
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,3,15,5);
// copy values to destination range
source.copyTo(destination, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}
The problem is, at the destination sheet, I still have columns A and B empty. By each row in the source (varies from time to time) copied, I need to place at column A todays date and column B the text "Review".
Like: Date (column A) | Revview (column B) | Pasted Data from Source (column C and other)
Do I need to write a completely new code to check for empty or can I implement both solutions into this code?
The code should fill the two cells before your data. It also caters for the setup where you have three areas in the same sheet.
Each copyInfoXd_button function will be assigned to your button image.
function copyInfo1d_button() {
copyInfo(2, "B1:B");
}
function copyInfo7d_button() {
copyInfo(9, "I1:I");
}
function copyInfo30d_button() {
copyInfo(16, "P1:P");
}
function copyInfo(startingCol, subjectCol)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Review");
var pasteSheet = ss.getSheetByName("Log");
const sourceCols = 4; //actual number of columns to copy, not including the empty column H
const destCols = 6; //actual number of columns to write to, from DATE to OBS
//find the last row from a colum
var avals = copySheet.getRange(subjectCol).getValues();
var lastRow = avals.filter(String).length;
var rowsToCopy = lastRow - 2; //skip the first 2 rows as they are headers
// get source range
var source = copySheet.getRange(3,startingCol,rowsToCopy,sourceCols); // row, column, number of rows and number of columns
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,rowsToCopy,destCols);
var data = [];
var sourceValues = source.getValues();
//construct new data for the destination range
for (var row in sourceValues) {
var destRow = [Utilities.formatDate(new Date(), ss.getSpreadsheetTimeZone(), 'MMMM dd, yyyy'), 'Review'];
destRow = destRow.concat(sourceValues[row]);
data.push(destRow);
}
destination.setValues(data);
}
I made it! I'm so proud! Thank you all for the help!
I'm beginning to do stuff like this!
After the Charles answer I looked for a way to add to each row. However, I know the code might not be too elegant, and I couldn't figured it out a way of doing using script itself, so I added a helper cell inside the sheet in H1 and H2.
Here's the solution:
function copyInfo24() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Review");
var pasteSheet = ss.getSheetByName("Log");
// get source range
var source = copySheet.getRange(4,2,99,5);
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,3,99,5);
// copy values to destination range
source.copyTo(destination, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
// Sets date at Column A and "Review" at Column B.
var data = [];
for(var i =0; i < copySheet.getRange("H1").getValue(); i++) {
data.push([Utilities.formatDate(new Date(), ss.getSpreadsheetTimeZone(), 'MMMM dd, yyyy'), 'Review']);
}
reviewRange = pasteSheet.getRange(pasteSheet.getLastRow()-copySheet.getRange("H2").getValue(), 1, copySheet.getRange("H1").getValue(), 2)
reviewRange.setValues(data); //set the date and 'Review' data
}
I got this script from "Delete Cells Based On Date" question that was asked. It deletes the actual row which removes all the formatting and variables. Is there a way to have it just remove the values?
Delete Cells Based on Date
This is the code:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Field1");
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();
var oneweekago = new Date();
oneweekago.setDate(currentDate.getDate() - 1);
for (i=lastrow;i>=2;i--) {
var tempdate = values[i-1][0];// arrays are 0 indexed so row1 = values[0]
and col3 = [2]
if(tempdate < oneweekago)
{
sheet.deleteRow(i);
}
}
}
What you're looking for is .clearContent() rather than deleteRow. This will only clear the contents of the cell, but leave all formatting in tact. Here's the Class Range documentation, it's really useful when looking at what you can do with a specific range in a sheet.
Now to get this to work the way you want, you'll have to use 2 for statements, one to get the row number (i), and the other to get the column number (j), which you can then use in the .getRange to run the .clearContent() on.
function clearOldRecords() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Field1");
var dataRange = sheet.getDataRange();
var lastRow = dataRange.getLastRow();
var data = dataRange.getValues();
var currentDate = new Date();
var oneWeekAgo = new Date();
oneWeekAgo.setDate(currentDate.getDate() - 7);
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].length; j++) {
var tempDate= data[i][0]; //column number is indexed from 0, change accordingly to your data
//if start date column is older than 7 days, clear the content of the row
if (tempDate!= "" && tempDate < oneWeekAgo) {
sheet.getRange(i+1,j+1).clearContent();
}
}
}
}
So, to explain this further, these are the notable changes I've made to your script.
Date subtractions are worked out in days, therefore doing a -1 will only take 1 day off of the date. You need a week so I have changed this to -7:
oneWeekAgo.setDate(currentDate.getDate() - 7);
The script also no longer scans the last row of the sheet, this could impact performance if the sheet is huge, but on your normal day-to-day sheet this shouldn't be an issue.
As you can see below, for loop for i gets all of the row numbers, and for loop j can be used for the column numbers, as you can see in the getRange() when trying to clear the contents:
sheet.getRange(i+1,j+1).clearContent();
Note: this may leave pretty huge gaps in your data if it's not sorted by date, you could add something like this to sort it afterwards (put this outside of the FOR loops):
sheet.getRange('A1:Z').sort({column: 2, ascending: false}) //change column number accordingly, this is NOT indexed from 0
I'm learning Google script as I go along and came across an issue that I could not find a solution for.
I have a function that takes in several several strings and one cell as params.
I assume passing a cell is not same as passing its value (string too btw)
Please find attached code:
//return id assigned to data(cell) sheetname
function findInColumn(column, data, colName, sheetname) {
/*
data = cell (cell value is 'bag_backpack.png') does not work
var range = SpreadsheetApp.getActiveRange();
var col = range.getColumn();
var row = range.getRow();
var range2 = SpreadsheetApp.getActiveSheet().getRange(row,col+1);
data = range2.getValue(); (cell value is 'bag_backpack.png') <---fail too
data = 'bag_backpack.png'; <---works
*/
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetname);
var column = sheet.getRange(column + ":" + column); // like A:A
var values = [];
for (var index = 0; index < column.getValues().length; index++) {
values.push(column.getValues()[index][0])
}
var colIndex = getByName(colName, sheetname);
var rowIndex = values.indexOf(data);
//grab id value of data
var range = sheet.getRange(rowIndex+1,colIndex+1);
var data = range.getValue();
return data
}
While I value and need your feedback I kindly request your bear in mind I'm a novice at best and I've spend several hours searching before asking here.
Thank you for your help.
Edit: bag_backpack.png is the content of a cell I'm searching in a column to get the row number of said cell.
var rowIndex = values.indexOf(data);
Returns the index I need.
However... if I feed a cell to the function instead of a string like a cell elsewhere with bag_backpack.png as its content or even derive said value from it:
var range = SpreadsheetApp.getActiveRange();
var col = range.getColumn();
var row = range.getRow();
var range2 = SpreadsheetApp.getActiveSheet().getRange(row,col+1);
data = range2.getValue(); (cell value is 'bag_backpack.png') <---fail too
In said case:
var rowIndex = values.indexOf(data);
gives out -1 instead of index desired.
Most of what you have doesn't make sense to me. I'm guessing that this is what you want. Since I can't figure out what you want, perhaps you can tell me what I missed.
function findInColumn(column,sheetname) {
var sh=SpreadsheetApp.getActive().getSheetByName(sheetname);
var rg=sh.getRange(column + ":" + column); /
var vA=rg.getValues();
var values = [];
for (var i=0;i<vA.length; i++) {
values.push(vA[i][0]);
}
return values
}
I want to thank everyone for taking the time to reply.
the issue was NOT with the code but with some of the first filename having uppercase in the id,name sheet while the binder sheet it did not.(at least 5 hours on Tent.png/tent.png)
I'm attaching a link to my finished work in hopes it benefits anyone.
https://docs.google.com/spreadsheets/d/1jCy1I4r6PeY3kUWrhNno2XO18Jghq6_b1kyN3AflidM/edit?usp=sharing
I'm trying to move a row of data from one sheet to another in the same spreadsheet based on a value of today's date.
In column "A", I have a date. I want to move the row if the date entered in column "A" is older than today's date. (it's a flight schedule for aircraft and I want to move flights that have already occured onto a sheet called "Past Flights".) The name of the active sheet is "Flight Schedule".
After the row is moved, I want it to delete off the "Flight Schedule" sheet. I know where to add scripts, but have no idea how to make this happen.
Here is what I have tried. I think on line "If (data.link >1..." data.link isn't the right one to use. But I can't find something for indicating older than todays date.
function approveRequests() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
if (sheetName == "Flight Shedule") {
var range = sheet.getActiveRange(),
startRow = range.getRowIndex(),
numRows = range.getNumRows(),
numCols = range.getNumColumns()
if (numCols == 9) {
if (data.length > 1) {
var values = range.getValues(),
nextSheet = ss.getSheetByName("Past Flight"),
lastRow = nextSheet.getLastRow();
nextSheet.getRange(lastRow+1,1,numRows,3).setValues(values);
sheet.deleteRows(startRow,numRows);
}
}
}
}
Any help would be huge!
Thanks!
Ok, I will go in with some general tips based on your current code first.
In your function you do a sheet = ss.getActiveSheet() which is redundant because you already have SpreadsheetApp.getActiveSpreadsheet().Also I would recommend to avoid this
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
in favour of this:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var sheetName = sheet.getName();
var data = sheet.getDataRange().getValues();
which is much more easy to read and change without making mistakes.
data.length has nothing to do with current date, it will simply be the length of the array. So if you select 1 row of data, it will be 1, if you select 2 rows it will be 2 etc. .getValues() will return an array where data[row][col]. What you are looking for is getting the value of the flight time, converting it into a date object (not a google specific thing, just general javascript). Then use var now = new Date() and compare the two.
I would also recommend to re-think your if statements. There are a lot of better ways to grab the row data than selecting the row manually and then running the function. You can save a lot of lines of code should you decide to actually make this run automatically, because as it is, it will run only when called manually.
This sample is working:
function approveRequests() {
// Initialising
var ss = SpreadsheetApp.getActiveSpreadsheet();
var scheduleSheet = ss.getSheetByName("Flight Shedule");
var pastSheet = ss.getSheetByName("Past Flight");
var lastColumn = scheduleSheet.getLastColumn();
// Check all values from your "Flight Schedule" sheet
for(var i = scheduleSheet.getLastRow(); i > 0; i--){
// Check if the value is a valid date
var dateCell = scheduleSheet.getRange(i, 1).getValue();
if(isValidDate(dateCell)){
var today = new Date();
var test = new Date(dateCell);
// If the value is a valid date and is a past date, we remove it from the sheet to paste on the other sheet
if(test < today){
var rangeToMove = scheduleSheet.getRange(i, 1, 1, scheduleSheet.getLastColumn()).getValues();
pastSheet.getRange(pastSheet.getLastRow() + 1, 1, 1, scheduleSheet.getLastColumn()).setValues(rangeToMove);
scheduleSheet.deleteRow(i);
}
}
}
}
// Check is a valid date
function isValidDate(value) {
var dateWrapper = new Date(value);
return !isNaN(dateWrapper.getDate());
}
So yes, It's not the optimized solution (cause of the use of several sheet.getRange() method), but it's working and allowing to have a clear code.
I have two sheets.
First is data from JSON with max results 100 rows. It contains 8 columns.
Second is the data I add manually and then write to the first sheet based on matched title.
For example, if both titles match then create a new column "Category" in first sheet from second sheet. The second sheet contains 50 rows and 8 columns.
When I run this script it throws error: We're sorry, we were unable to process the operation because it contains too much data. I tried to remove line by line to figure out what is causing it. And it seems like when I remove this line:
data[i][11] = descr; // this is a paragraph long description text
It is working fine. Also, if I remove all the other data I want to write in, and run only data[i][11] = descr; it also chokes. So, it doesn' seem like there is too much data. Any ideas how to make it work? Workarounds?
Edit: here is a copy of the spreadsheet:
https://docs.google.com/spreadsheet/ccc?key=0AhVWrVLsk5a5dFRaeFQxZUc3WlZOR0h4N09pOGJBdGc&usp=sharing
Thanks!
function listClasses(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //list of all upcoming classes
var sheet1 = ss.getSheets()[1]; //list of titles
var data = sheet.getDataRange().getValues(); // read all data in the sheet
var data1 = sheet1.getDataRange().getValues();
for(n=1;n<data1.length;n++){
var title1 = data1[n][0];
var category = data1[n][1];
var image_url = data1[n][2];
var available = data1[n][3];
var descr = data1[n][4];
var prerequisites = data1[n][5];
var mAccess = data1[n][6];
var notes = data1[n][7];
// compare Check if title appears in column B of sheet 1.
if (ArrayLib.find(data1, 0, title1) != -1) {
// Yes it does, do something in sheet 0
for( var i = data.length -1; i >= 0; --i )
if (data[i][1] == title1)
{
//Logger.log(descr);
if (data[i].length < 14){
data[i].push(' ');
}
data[i][8] = category;
data[i][9] = image_url;
data[i][10] = available;
data[i][11] = descr;
data[i][12] = prerequisites;
data[i][13] = mAccess;
data[i][14] = notes;
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}
}
}
I had a look at your code, but I could not make it work.
I too get such error messages, but so far have encountered them when I am processing a few thousand rows (with only 4 columns) but each row containing as much text or more than your description.
I only know how to use a simple way, which I tried for your case too. The following code I think does what you need:
function listClasses2(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //list of all upcoming classes
var sheet1 = ss.getSheets()[1]; //list of titles
var data = sheet.getDataRange().getValues(); // read all data in the sheet
var data1 = sheet1.getDataRange().getValues();
var newDataArray = [data[0]];
for(var n=1; n < data.length ; n++){
for(var j=0; j< data1.length ; j++){
if(data[n][1] == data1[j][0]){
newDataArray.push([data[n][0] ,data[n][1] ,data[n][2] ,data[n][3] ,data[n][4] ,data[n][5] ,data[n][6] ,data[n][7] ,data1[j][1] , data1[j][2] , data1[j][3] , data1[j][4] , data1[j][5] , data1[j][6], data1[j][7] ]) ;
break;}
}
newDataArray.push(data[n])
}
sheet.getRange(1, 1, newDataArray.length, newDataArray[0].length).setValues(newDataArray);
}
(I have just noticed that my var n is not the same as your var n ... sorry for the possible confusion)