Compare data (two cells) every week automatically in Google Sheet - google-apps-script

I am using Google Sheet to manipulate data. I would like to automate one of my tasks.
Every Monday I check if my data has increased or decreased, for that I use a file that updates my data every week in a different row.
I would like to compare the last week with the one before. Basically, I would like to run a script that understands to compare one cell with the one right before so that I don't have to do it manually every week.
How can I do this with Google App Script ?
Thank you for your help!
Natacha

You can set up a Time-driven trigger to run once a week.
To compare one cell contents with another, you can use the getValue() method of the Range class:
const range1 = sheet.getRange("A1").getValue() // for example
const range2 = sheet.getRange("A2").getValue()
if (range1 < range2) {
}
else if (range1 > range2) {
}
// etc

Related

How to stop formulas from updating at a certain time each day in Google Sheets?

I want Google Sheets to stop updating a formula in a cell corresponding to the current date at a certain time each day, but I am not well versed in scripting so I need some help. I have some examples of my data below.
I have a sheet "Time Spent in Statuses" that automatically updates every hour (with a google sheets extension). New 'Keys' are added to the sheet when they are added in the extension, i.e Key '5' doesn't exist now, but when someone creates it in the data source linked with the extension, Key '5' and its corresponding values will be automatically added, so it updates frequently with more data.
In a separate sheet, I track the daily averages of numbers from the auto update in a sheet "Daily Averages" .
Currently in the "Daily Averages" sheet, I use a formula to calculate the average of each column in the "Time Spent in Statuses" sheet. This formula is pre-filled for days upcoming. At the end of each day, I have to go to this sheet and Copy and Paste > Values Only to record the averages for that day and stop the formula from continuing to update the next day. I use the 'Date' column and the Avg columns to show change in the daily averages over time in a dashboard.
What I'm looking for is some kind of logic that will look at the 'Date' column in the "Daily Averages" sheet and if it equals the current date and the time is 11:59 pm (or some other set time), then automatically Copy and Paste > Values Only. Or something similar so that I don't have to go in and manually paste values only every day. Does anyone have any experience doing something like this?
What you're looking for is a time-driven trigger in Apps Script. You can write a script and set it to run daily at a specific time.
There are multiple approaches that you can take when writing the script, but based on the sample that you provided, you can try the following code:
function setDailyAverage() {
let ss = SpreadsheetApp.getActiveSpreadsheet()
let avgsheet = ss.getSheetByName("Daily Averages")
//this is a string with today's date in format mm/dd/yyyy, like in your sample
let today = new Date().toLocaleDateString("en-US")
//this will do a search of today's date and return the row number
let row = avgsheet.createTextFinder(today).findNext().getRow()
let avgcell = avgsheet.getRange(row,2) //gets column 2 in the row corresponding to today
let giavgcell = avgsheet.getRange(row,3) //gets column 3 in the row corresponding to today
//This reads the values in each cell and overwrites the formula with the actual value
avgcell.setValue(avgcell.getValue())
giavgcell.setValue(giavgcell.getValue())
}
To add the script go to Extensions > Apps Script and paste it there, then on the left side go to Triggers > Add Trigger, then the trigger settings should look like this:
This would run the script every day between 11pm and midnight, and pretty much just automate the same "Copy and Paste > Values Only" process that you're following. You still would need to have the pre-filled rows for each date so keep that in mind. With the trigger you could also automate the creation of each row daily but I don't know if this would interfere with your workflow.

How do you track automated data inputs in Google Sheets over time?

I have a google sheet that runs a report on data that is automatically updated. What I would like to do is compare the new inputs with the old inputs to determine if the changes were positive or negative. How would you go about automating a sheet to track these changes?
Changes happen monthly
there would be a score 1-100; 100 being the best
would like to store this data over time for a historical view
Any advice would surely be appreciated
The numbers in each criteria change every month producing a score at the end of the table called Current Score
This score is then pulled into the historical tab as the "Current Score"
What I would like to see happen is that the Current score be saved every month and processed with a percentage change month over month
So I would need a function that stores a copy of the results before they change, processes a new score, and then calculates the difference between the two. Example here is the Dec score (stored values) compared to the most recent score.
Here is a link to the working example
https://docs.google.com/spreadsheets/d/1ImbRhWqGjvIx2CFRKapZ2wmxC9qpSKxxCbHr5tPOBOs/edit#gid=0
Solution
You can automate this process by using Google Apps Script. Open the script editor by clicking on Tools > Script Editor. It is based on JavaScript and allows you to create, access and modify Google Sheets files with a service called Spreadsheet Service.
In addition, you can use Time-driven triggers to run the script automatically once a month. To set it up, click Triggers in the left bar, then Add Trigger and select Time-driven in Select event source. You can now specify the month timer and the exact day and hour you want the script to run. However, I recommend that you do some testing before setting up the trigger to check that you get the desired results. You can test the code by clicking Run in the Editor.
Explanation of the code
There are three functions in the code. The main function is called updateScores and it does what you described in the question. It takes the current score, stores it in a new column and calculates the difference from the last month. Try this function and if you like the result, you can put the trigger in the main function. This way, the trigger calls main which its only responsibility is to call the other two functions. The first is updateScores, which I have already explained, and the second is clearScores, which clears all the values of Reports so you don't have to do it manually and you can start writing the new values for the new month.
I have added some comments so you can understand what each line does.
var lr = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('report').getLastRow()
function updateScores() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Historical')
var currentValues = ss.getRange('B2:B'+lr).getDisplayValues() // get current score
ss.insertColumnsAfter(2,2) // insert two new columns (current score and percent difference)
ss.getRange('D2:D'+lr).setValues(currentValues) // paste stored score
ss.getRange('C2:C'+lr).setFormula('=if(D2=0,"N/A",B2/D2-1)') // apply formula for last stored scores
ss.getRange('E2:E'+lr).setFormula('=if(F2=0,"N/A",D2/F2-1)') // correct formula reference
ss.getRange('E2:E'+lr).copyFormatToRange(ss,3,3,2,lr) // copy format percent
ss.getRange('F2:F'+lr).copyFormatToRange(ss,4,4,2,lr) // copy format scores
var month = new Date().toString().split(' ')[1] // get current month
ss.getRange('D1').setValue(month + ' score') // write current month on last stored scores
var diff = ss.getRange('E1').getDisplayValue() // get diff symbol
ss.getRange('C1').setValue(diff) // write diff
}
function clearScores(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('report')
ss.getRange('B2:G'+lr).clear()
}
function main(){
updateScores()
clearScores()
}

Google Sheets: Hiding Columns based on date in row 1

I have no experience with scripting in Excel or Google Sheets, so I'm trying to branch out a bit and see if there's a solution to my problem. We use Google Sheets for a weekly calendar at our kitchen remodeling business. We organize the weeks from left to right and list the jobs we're currently working on in those columns. I would like to automatically hide all columns that have a date older than 4 weeks, so when the sheet opens, we're not starting with a date from a year ago. I can hide these columns manually each week, but when I do need to go back and look at previous weeks, I'm forced to unhide all thosecolumns and then highlight all of the columns I want to rehide. Having a script seems like the better solution.
Is there a way to have a script run every time the file is open so that we're always only displaying the previous 4 weeks and everything in the future? If so, would you be willing to help me understand how I might write that and get it working? Again, I'm a novice when it comes to anything beyond formulas, but very interested in learning more about the scripting capabilities.
Thank you!
With Apps Script via Tools->Script Editor, you could create a menu with an onOpen() function. The function in the menu (e.g. hidePast), would then need to check a given value in each column (to see what date that column refers to), and then flag it to be hidden or not. The onOpen function, because it is a "simple trigger", cannot do anything that requires "authorization" (such as interacting with non-local Spreadsheet data), hence the intermediate method. By creating a menu, you can make it easy for anyone using the spreadsheet to authorize and activate the function.
Example:
/* #OnlyCurrentDoc */
function onOpen() {
SpreadsheetApp.getActive().addMenu("Date Tools",
[{name:"Hide Past", functionName:"hidePast"},
{name:"Show All", functionName:"showAll"}]);
}
function showAll() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
sheet.unhideColumn(sheet.getDataRange());
ss.toast("All columns unhidden.");
}
function hidePast() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
// Acquire the 1st row of all used columns as an array of arrays.
var datelist = sheet.getSheetValues(1, 1, 1, sheet.getLastColumn());
// Drop the hours, minutes, seconds, etc. from today.
var now = new Date();
var today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
// Inspect the datelist and compare to today. Start from the rightmost
// column (assuming the dates are chronologically increasing).
var col = datelist[0].length;
while(--col >= 0) {
var then = new Date(datelist[0][col]);
if(then < today) {
break;
}
}
// Bounds check, and convert col into a 1-base index (instead of 0-base).
if(++col < 1) return;
// col now is the first index where the date is before today.
// Increment again, as these are 2-column merged regions (and
// the value is stored in the leftmost range). If not incremented,
// (i.e. hiding only part of a merged range), spreadsheet errors will occur.
sheet.hideColumn(sheet.getRange(1, 1, 1, ++col));
ss.toast("Hid all the columns before today.");
}
Because you don't have a "database like" source it will be very difficult, but you can try to create a very complicated
QUERY()
you should filter the dates in another sheet (and you may face a dead end).
So I will suggest using this kind of structure and it will also allow you to make other kinds of filters (or Pivot Tables) in the future (maintainable and scalable).

Creating a script that runs every second

I am trying to create a script that edits a particular cell on a particular sheet every second with a random text like, "SetTime".
This Particular Cell is: X2
This Particular Sheet is: "System_Info"
You may ask why I need this, essentially, I have a cell that displays a time using the =NOW formula. When a spreadsheet is edited, it will refresh the =NOW formula.
So, I need a script that loops every second and runs a function that edits that cell.
I've used this:
setInterval(function(){ SpreadsheetApp.getSheet("System_Info").getRange('X2').setValue('SetTime'); }, 1000);
However, set interval is not defined.
Thanks for any help,
Shaun.
you are mixing server with client code. even if you use time driven apps script triggers its not possible because they run at most once a minute, and changes through api do not cause a refresh.
Alternative: go to spreadsheet menu,file,properties. Select the option to update calculated functions every minute. No script needed.
Here is a function that will update the time in a cell every second for 15 seconds. It should be at least a starting point for you.
function updateCell() {
for (i=0; i<15; i++){
Utilities.sleep(1000);
var date = new Date();
SpreadsheetApp.getActiveSheet().getRange("A1").setValue(date);
SpreadsheetApp.flush();
}
}

Beginner in desperate need: pastevalue() to create historical tab for investments

Thank you very much in advance for your help, I'm new to coding but proficient with standard Excel functions. I would greatly appreciate any input on this project.
I want to create a Google spreadsheet that has 3 sheets. The first is a DATA sheet which lists stock tickers and provides live prices via Google finance {=googlefinance(VTI,price)}.
The second sheet is the MASTER sheet that aggregates all of the positions, including number of shares in stocks, quantity in fixed income instruments, quantity in bullion, etc. The prices used to calculate current market value of positions are drawn from the DATA sheet. All values are added together to create a total value cell, E57, that updates itself automatically from the google finance data throughout the trading day. This all works fine.
The final sheet is the HISTORY sheet. Here's what I want to do. I want cell E57 to copy to this sheet once a day at market close so I have a daily history of the aggregate portfolio. Each time the script copies and pastes the value to the HISTORY sheet, it needs to paste on the next available row in the same column. So far, I've written a script that successfully copies and pastes the value at a defined time interval (using Project Triggers), but it just keeps pasting over the previous value. How can I make it paste to each successive open cell and generate a list?
Also, I need all of this to work without me signing in or opening/activating the sheet. I want it to run completely autonomously, that's why I'm activating the sheet via openById instead of using the ActiveSheet code (I think that reasoning is correct, but not sure).
Here's the script I have:
function PasteValue() {
var ss = SpreadsheetApp.openById("0Ao2pCtssx6TcdGpDWFpSXy1pUXA3MlAtSjZFVHlaZVE");
ss.getRange("MASTER!E57").copyTo(ss.getRange("HIST!C5"),{contentsOnly:true});
}
What do I do to improve?? Thank you!​
Your code suggests the name of the history sheet is HIST.
I think there are a few ways to do this:
Option 1:
Uses the getLastRow() method
function PasteValue() {
var ss = SpreadsheetApp.openById("0Ao2pCtssx6TcdGpDWFpSXy1pUXA3MlAtSjZFVHlaZVE");
var nextRow = ss.getSheetByName('HIST').getLastRow()+1;
ss.getRange("MASTER!E57").copyTo(ss.getRange("HIST!C" + nextRow),{contentsOnly:true});
}
Note that option 1 will not work if you have a column of cells that contain formulas that have been copied down to the bottom of the sheet.
Option 2:
Loops through the cells in column C to find the first blank cell.
function PasteValue() {
var ss = SpreadsheetApp.openById("0Ao2pCtssx6TcdGpDWFpSXy1pUXA3MlAtSjZFVHlaZVE");
var values = ss.getRange("HIST!C:C").getValues();
for (vari=0; i<values.length; ++i) {
if (values[i][0] == "") {
var nextRow = i+1;
break;
}
}
ss.getRange("MASTER!E57").copyTo(ss.getRange("HIST!C" + nextRow),{contentsOnly:true});
}
Option 2 should work as long as you have no blank cells in column C.
Option 3:
Use the appendRow() method
Good luck!