I have a spreadsheet that I would like to autosort based on date, delete duplicate rows, and delete rows if the date listed has passed. I have the autosort and deleting duplicates, I just need help with deleting rows based on the date. It will delete all rows except row # 2, regardless of date.
So far I have:
function deleteRow1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow()-1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 2, numRows);
var data = dataRange.getValues();
for (i = 0; i < data.length; i++) {
var row = data[i];
var date = new Date();
var sheetDate = new Date(row);
var Sdate = Utilities.formatDate(date, 'EST-0500', 'MM:dd:yyyy')
var SsheetDate = Utilities.formatDate(sheetDate, 'EST-0500', 'MM:dd:yyyy')
if (Sdate > SsheetDate) {
sheet.deleteRow(i + 2)
}
}
}
So here is about what it could look like, I think. I changed as little as I could about your routine, focusing on the parts that seemed like they were troubling.
In particular, dates are compared to dates, with times removed/equated. Also, it bothered me to repeatedly construct today, so I took that outside the loop.
Also, I worked from the bottom up to make sure deletions did not affect which row to consider next.
function deleteRow1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow()-1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 2, numRows);
var data = dataRange.getValues();
var today = new Date();
today.setHours(0,0,0,0);
for (i = data.length-1; i > -1; i--) {
var row = data[i];
var sheetDate = new Date(row);
sheetDate.setHours(0,0,0,0);
if (today > sheetDate) {
sheet.deleteRow(i + 2)
}
}
}
It might be a nice touch to change i+2 to startRow+i.
Related
I am having a google response sheet. I run this sheet every night at 12. whenever some response are received I want to append the row to another sheet and delete the respective row in form responses. Here I want to start appending from the oldest timestamp in form responses i.e. from row number two as row number 1 is questions. whenever Irun this code, I am successfully appending the row but not able to delete the row.
Here is the code I am trying to do:
//** Copying the response to another Spreadsheet for roster management**//
function copySheet(){
var source = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = source.getSheetByName("Form Responses 1");
var lastRow = sourceSheet.getLastRow();
var getData = sourceSheet.getDataRange().getValues();
var destSheet = source.getSheetByName("10017135ADC");
Logger.log(lastRow);
if(lastRow >1){
for (var j =1; j<lastRow; j++) {
// Logger.log(j);
var rowData = getData[j];
// Logger.log(rowData);
destSheet.appendRow(rowData);
sourceSheet.deleteRow(j);
}
}
}
Try this:
function copySheet(){
var source = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = source.getSheetByName("Form Responses 1");
var lastRow = sourceSheet.getLastRow();
var getData = sourceSheet.getDataRange().getValues();
var destSheet = source.getSheetByName("10017135ADC");
Logger.log(lastRow);
let d=0;//keep track of deleted rows
if(lastRow >1){
for (var j =1; j<lastRow; j++) {
// Logger.log(j);
var rowData = getData[j];
// Logger.log(rowData);
destSheet.appendRow(rowData);
sourceSheet.deleteRow(j-d++);
}
}
}
Cooper's new variable approach was good. But upwards for deletion is a better approach.
Try something like this
for (var i = getData.length - 1; i > 1; i--) {
//anything you want to perform
destSheet.appendRow(getData[i]);
sheet.deleteRow(i);
}
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 trying to move multiple rows simultaneously from one Google sheet to another.
I would like to run the script once at the end of day to archive all the complete jobs.
The script I've put together will only move 2 rows at a time as long as the targeted cell is not blank. Ideally, it would continue to loop and only move the jobs marked 'Complete'.
The sheet I'm using is here
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Admin')
.addItem('Archive', 'archive')
.addToUi();
}
function archive()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Scheduled");
var range = sheet.getRange('A5:Q200');
var sheetToMoveTheRowTo = "Archive";
var numRows = sheet.getLastRow();
var row = sheet.getRange(5,1);
for (var row = 5; row < numRows; row++)
{
var status = sheet.getRange(row,1).getValue();
if ( status == "Complete") {
var targetSheet = ss.getSheetByName(sheetToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(),1,1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(range.getRow());
}
}
}
Archive, Google Sheets, Move, Rows, Spreadsheet, Delete
You should set all the data to archive in one operation. You can't delete all the rows in one operation, but you can save what rows to delete and then loop through the row numbers.
Link to Publicly Shared Spreadsheet with Code
I'd set up the code to be structured like this:
function archive() {
var arrayOfRowsToArchive,data,i,lastColumn,L,numRows,range,rowsToDelete,
ss,sheet,sheetToMoveTheRowTo,startRow,status,targetSheet,thisRowsData;
//USER INPUT:
startRow = 5;
//END OF USER INPUT
ss = SpreadsheetApp.getActiveSpreadsheet();
sheet = ss.getSheetByName("Scheduled");
sheetToMoveTheRowTo = "Archive";
numRows = sheet.getLastRow();
lastColumn = sheet.getLastColumn();
arrayOfRowsToArchive = [];
rowsToDelete = [];
data = sheet.getRange(startRow, 1, numRows - startRow, lastColumn).getValues();//Get all values except the header rows
L = data.length;
for (i=0; i < L; i++) {
status = data[i][0];
//Logger.log('status: ' + status);
if ( status === "Complete") {
thisRowsData = data[i];//Only get inner array of data
//Logger.log('thisRowsData: ' + thisRowsData)
arrayOfRowsToArchive.push(thisRowsData);//Push one row of data to outer array
rowsToDelete.push(i+startRow);//Get the row number to delete later
}
}
targetSheet = ss.getSheetByName(sheetToMoveTheRowTo);
targetSheet.getRange(targetSheet.getLastRow()+1, 1, arrayOfRowsToArchive.length, arrayOfRowsToArchive[0].length)
.setValues(arrayOfRowsToArchive);
//Logger.log('rowsToDelete: ' + rowsToDelete)
for (i=rowsToDelete.length;i>0;i--) {//Delete from bottom up
Logger.log((i-1).toString())
Logger.log('rowsToDelete[i-1]: ' + rowsToDelete[i-1])
sheet.deleteRow(rowsToDelete[i-1]);
}
}
I want a Google Script which checks once a day on my spreadsheet and copies the values to another sheet and than deletes all the rows if the date in that cell is small than the current.
The file looks like this:
And this is what I wrote so far:
function DeleteIfDateIsToSmall(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
var today = new Date();
var today2 = Utilities.formatDate(today,'GMT+0200','dd.MM.yyyy');
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow()-1
for (var i=2; i < numRows; i++) {
var DateCell = s.getRange(i, 13);
var sheetDate = DateCell.getValue()
var sheetDate2 = Utilities.formatDate(sheetDate,'GMT+0200','dd.MM.yyyy');
var row = i;
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Ended or Deleted");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
if (s.getName() == "Start" && sheetDate != 0 && sheetDate != "" && today2.valueOf() > sheetDate2.valueOf()){
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
}
It doesn't seem to work, please help.
A few things are wrong or suboptimal here.
For a timed trigger, the event object does not have any range/source data; it only has time data. You need to pick a sheet by name (or loop through all sheets obtained by getSheets, if this is what you want).
Utilities.formatDate returns a string, which is not the best way to compare dates; in any case calling valueOf on it seems pointless.
Instead of using getValue in a loop, it is more efficient to obtain values before entering the loop, with getValues. There are some other things you do in the loop that should be outside.
Deleting rows when moving top to bottom in a sheet is tricky, because rows shift, messing up their indexing. For this reason, I collect the rows to be deleted in an array, and then delete them in bottom-to-top order.
function DeleteIfDateIsTooSmall() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Start");
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Ended or Deleted");
var today = new Date();
var dates = s.getRange(2, 13, s.getLastRow()-1, 1).getValues();
var rowsToDelete = [];
for (var i = 0; i < dates.length; i++) {
if (dates[i][0] && dates[i][0] < today) {
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(i + 2, 1, 1, numColumns).moveTo(target);
rowsToDelete.push(i + 2);
}
}
for (i = rowsToDelete.length - 1; i >= 0; i--) {
s.deleteRow(rowsToDelete[i]);
}
}
Apologies in advance - I am not a programmer. Just trying to piece together something for my business. Currently, I have a script that references a spreadsheet and sends out an automated email to my receptionist. This script provides all of the information I'd like it to but problem is that it sends out a separate email for every entry. Ideally, I would like to send a single email to my receptionist that contains a list of all of the appointments for the upcoming day.
Issues I'm having include:
I need to consolidate multiple emails into a single email containing a list of the upcoming appointments for the next day.
I don't know how to select the rows I need because they are date values (DD/MM/YYYY). So I'm Looking for a way to read the date, recognize that it is one day before the appointment, and add these entries to a single list.
If anyone can help me out with this it would be greatly appreciated!
Here's what I have so far:
function receptionist() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[2];
var timeslot = sheet.getRange(i+2,7,1,1).getValues();
var name = sheet.getRange(i+2,2,1,1).getValues();
var date = Utilities.formatDate(new Date(sheet.getRange(i+2,6,1,1).getValue()),"EST", "E MMM dd, yyyy");
var receptionist= name+" scheduled on "+date+" at "+timeslot;
var subject = "Appt. List";
var emailAddress = "receptionist#example.com";
MailApp.sendEmail({emailAddress, subject, receptionist});
Thanks in Advance!
I've tested this code, and it works:
function receptionist() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
var data = dataRange.getValues();
var receptionist = "Today's Appointments \r\r";
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[2];
var timeslot = sheet.getRange(i+2,7,1,1).getValue();
var name = sheet.getRange(i+2,2,1,1).getValue();
var dateData = sheet.getRange(i+2,6,1,1).getValue();
var dayOfAppointment = dateData.getFullYear() + dateData.getMonth() + dateData.getDate();
var todaysDate = new Date();
var todaysDayNumber = todaysDate.getFullYear() + todaysDate.getMonth() + todaysDate.getDate();
if (todaysDayNumber === dayOfAppointment) {
var date = Utilities.formatDate(new Date(),"EST", "E MMM dd, yyyy");
var thisAppointment = name+" scheduled on "+date+" at "+timeslot + "\r";
receptionist+=thisAppointment;
};
};
var subject = "Appt. List";
var emailAddress = "receptionist#example.com";
MailApp.sendEmail(emailAddress, subject, receptionist);
};
You do need a for loop. I removed the curly braces from the .sendEmail() parameters. Note the "\r" values to wrap each line to a new line. This Line:
receptionist+=thisAppointment;
makes the receptionist variable longer by one appointment line on each iteration. I didn't go through every line of code to determine whether the code is optimal or not. The basics of what you need are there. It may work "as is".