for example i have this table
a
b ( value per second )
c (final result)
1
12.5
25
i want to add cell b1 to c1 every second or minute ( both type will be perfect )
so c1 should be 12.5 , 25 , 37.5 , 50 , etc ... every second or minute
i tried to search it , i couldn't find something useful
is there any formula?
I'm not too sure about a formula that can do this, but I know this can be done fairly easily in Apps Script, so that's what I've done.
Script
All you'll have to do yourself is fill out the name of the sheet you want to work on in the code, which I've commented in the code itself for you.
It'll then grab all needed data and run through it, adding the B column to the C column all the way down.
function adding() {
// variables
const sheetName = 'name of sheet';
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
// goes from B2 to the last row that has any input and is 2 columns wide
const range = sheet.getRange(2, 2, sheet.getLastRow() - 1, 2).getValues();
let counter = 2;
for (const row of range) {
sheet.getRange(`C${counter}`).setValue(row[0] + row[1]);
counter++;
}
}
Trigger
In order to make this work every minute (second based isn't possible with triggers) you'll have to setup a trigger event.
How to get to triggers
On the left hand side in the script editor you can select Triggers with the little clock icon. This will take you to the triggers page where you can create a new one in the bottom right.
Setup trigger
Make sure to select the right function and to change the event source to time-driven. Now you chose how often you want it to run, which can be once a minute.
Related
I use importrange for combine 2 google sheet Target A and Source B
In sheet A =
Importrange(“linkgooglesheetB”,”SheetB!!A2:M1000)
It’s done
But when data in sheet Source B cleared/changed, then
Data in sheet Target A cleared/changed too
What formula can use same my above formula but data in Target A do not change after combined (A&B), when B changed.
Answer:
You can do this with Google Apps Script.
Explanation:
The IMPORTRANGE formula will always automatically update when the range from which it is importing had a data change. In fact, this is a feature of all sheet formulae; they are designed to keep everything up-to-date when data changes.
For this reason, you can not use a formula. You will have to do this using Google Apps Script.
Example code:
The idea is as such:
When the sheet is edited, a script will run.
If the cell data matches a certain pattern, then the script will paste in the data permanently, in the same way that IMPORTRANGE works.
function runOnEdit(e) {
// We will make the patten here. In this case, the text entered in the cell must be of the form:
// "IMPORT(link,range)
// example:
// IMPORT,https://docs.google.com/spreadsheets/d/some-id/edit, SheetB!A2:M1000
const patternStart = "IMPORT"
const compareVals = e.value.split(",")
if (compareVals.length != 3 || compareVals[0] != patternStart) return
try {
const ss = SpreadsheetApp.openByUrl(compareVals[1])
const importRange = compareVals[2].split('!')
const sheetName = importRange[0]
const range = importRange[1]
const sheet = ss.getSheetByName(sheetName)
console.log(sheetName)
console.log(range)
const data = sheet.getRange(range).getValues()
const formatting = sheet.getRange(range).getTextStyles()
const activeSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
const row = e.range.getRow()
const col = e.range.getColumn()
activeSheet.getRange(row, col, data.length, data[0].length).setValues(data).setTextStyles(formatting)
}
catch (err) {
e.range.setValue(err)
}
}
Things to note:
The pattern can not start with an = as this will be read as a formula by Sheets and throw an error.
This must be set up as an installable trigger, as opening a separate Spreadsheet requires authorisation, which can not be done from a simple trigger.
You can install the trigger by clicking on the clock logo in the left toolbar from the Apps Script editor, then clicking + Add Trigger in the bottom right and using the following settings:
Choose which function to run: runOnEdit
Which runs at deployment: Head
Select event source: From spreadsheet
Select event type: On edit
Visual example:
Most of the formula is live update, including query function. However in order not to have your data change for importrange, there is two possible solution:
1)Create a backup sheet by copy paste data from the main sheet, and importrange from the backup sheet, so any change in main sheet will not have impact on your result
2)Write Google App Scrip to copy data, but it take time to learn
Let's say I have a table:
Quantity
Item
Value
Fetched Item
Suggestion
5
Meat
Variable
Meat
...
The cells in the Value column have a VLOOKUP formula to fetch the value of items with the same name as "Item", and returns "Variable" if there isn't a good fit (which means there are multiple options). The Cells in the Suggestion column have a VLOOKUP formula to fetch the lowest value item in a category with the same name as "Item", and returns "" if there isn't such a category (which means the item would have been found in the value column's search). After the search, the table looks like this:
Quantity
Item
Value
Fetched Item
Suggestion
5
Meat
Variable
Meat
Cow Meat
Now, columns D and E aren't going to be used, so the user changes column B to have the suggested item.
Quantity
Item
Value
Fetched Item
Suggestion
5
Cow Meat
300
Meat
Cow Meat
So I don't want the user to have to put "meat" in the "Fetched Item" column for it to work, so let's say that column just has a simple =B2 formula in it. The sheet now looks like this:
Quantity
Item
Value
Fetched Item
Suggestion
5
Cow Meat
300
Cow Meat
However, the sheet that the Suggestion formula references updates the values regularly, so fast forward to the point where cow meat now costs more than pig meat. I want the table to look like this:
Quantity
Item
Value
Fetched Item
Suggestion
5
Cow Meat
300
Meat
Pig Meat
This way, the user can update column B accordingly. This means that I need some way for column D to automatically copy the content of column B if column C reads "Variable", while ignoring future changes to column B.
=IF($C5="Variable",[copy $B5],"")
Something like this, I guess? I guess the easiest way to put this is "Is there a way to automatically run a formula a single time?", which is better than my old title of "Take a "snapshot" of data when referencing a cell so it doesn't change if the referenced cell does?", so I've changed it accordingly.
Using onEdit:
You could use an onEdit trigger, using Apps Script (click Tools > Script editor, copy the function below and save the project).
(For this to work, please create a new column (G), which will be used to store information on whether there were previous copies. You can then hide it.)
This function would execute every time a user edits the spreadsheet, and it would do the following, using the event object:
Check whether edited column corresponds to Item and edited column is your desired sheet (column C and sheet Recipe Cards in the spreadsheet you provided).
If that's the case, check whether Value column (D) is equal to Variable and column G is equal to a certain string (called Avoid future updates in the sample below).
If that's the case, set the value from C to E and write Avoid future updates to column G.
Code snippet:
function onEdit(e) {
const range = e.range;
const sheet = range.getSheet();
const rowIndex = range.getRow();
const colIndex = range.getColumn();
const avoidUpdateColumn = 7;
const itemColumn = 3;
const valueColumn = 4;
const fetchedItemColumn = 5;
const copyValue = "Variable"; // Do not copy if column doesn't have this value
const avoidUpdateValue = "Avoid future updates"; // Do not copy if column has this value
const sheetName = "Recipe Cards";
if (colIndex === itemColumn && sheet.getName() === sheetName) {
const numCols = sheet.getLastColumn()-colIndex+1;
const rowValues = sheet.getRange(rowIndex, colIndex, 1, numCols).getValues()[0];
if (rowValues[valueColumn-itemColumn] === copyValue && rowValues[numCols-1] !== avoidUpdateValue) {
sheet.getRange(rowIndex, fetchedItemColumn).setValue(rowValues[0]);
sheet.getRange(rowIndex, avoidUpdateColumn).setValue(avoidUpdateValue);
}
}
}
Reference:
Spreadsheet Service
Simple Triggers
I use a daily (01:00 am) script to record my daily portfolio value, calculated in sheet A, to a new sheet.
Every day the script runs, opens a new line and records the value in column A, but I have to add the date manually on column B.
The document looks like that:
A-----------B
$1000-----1.1.2019
$1004-----1.2.2019
... ------....
$1006-----1.5.2019
I couldn't find a way to automatize column B date recording. What should I add to my code?
function copy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange ("calc!U12");
var data = source.getValues();
var ts = ss.getSheetByName("record");
ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length).setValues(data);
}
This can be solved without using script. In cell B1 put your starting date. In all of the other cells in B, drag down this formula:
=IF(COUNTBLANK(A2)=0,B1+1)
This checks to see if the cell to the left (in A) has a value, and if it does, it will add one to the previous date. The first date will still have to put in by hand. You may want to make column B formatted so that the numbers appear as dates.
Formula: In cell A1 I manually type the date that I'm adding a new value, in cell B1 I have the Today() formula, and finally in cell C1 I have the formula =YourStartingValue - (5*(B1-A1)).
Result: The end result is that the value I input into cell C1 gets 5 subtracted from it each new calendar day. I then repeat this step in a new row for each new value that I add.
My question: is there a formula I can use so that I don't have to add the stuff in A1 and B1 each time? It'd save time and make things cleaner. Thanks!
In order to have 5 subtracted from every value in some column every day, I would use a script such as this one:
function subtractDaily() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var range = sheet.getRange('C:C');
var values = range.getValues();
range.setValues(values.map(function(row) {
return [row[0] == parseFloat(row[0]) ? row[0] - 5 : row[0]];
}));
}
Change the sheet name and column as needed, and set it to run daily using "Resources > Current project's triggers" dialog of the script editor.
The script checks that the cells contain numbers and does not attempt to subtract 5 from text or blank cells.
I need to introduce functionality into a google spreadsheet that will allow the user to edit the result of an array formula. The reason for the requirement is that an ARRAYFORMULA sets a default value for a group of cells, but the user sometimes needs to overwite these defaults. I'd like to know if this is even remotely possible.
example:
Row(#)|Array_1 |Array_2
------------------------------------
1 |a |=arrayformula(Array_1)
2 |b |""
3 |c |""
4 |d |""
So all rows in Array_2 are populated by an array formula. However the user wants to go directly to the second cell in Array_2 and change its value. Of course, by design ARRAYFORMULA will break. Is there some way to modify ARRAYFORMULA, so that it will simply skip over the cell that the user has edited and continue on its way as if nothing has happeded?
I realize this is an old problem but I was searching for this today and made a script that works for me.
This script puts a formula in an adjacent cell when a cell is edited in the second column. This way you can just overwrite the formula if you need to input something manually and you don't need to have the formulas go into all of the rows beforehand. I had people accidentally edit the formula and mess it up most of the time when they were pre-filled, so this works better for me.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetList = ["Sheet1","Sheet2","Sheet3"]; // list of sheets to run script on
for (i = 0; i < sheetList.length; i++) {
var sheetName = ss.getSheetByName(sheetList[i]);
// only runs if sheet from sheetList is found
if (sheetName != null) {
var aCell = sheetName.getActiveCell();
var col = aCell.getColumn();
var adjacentCell = aCell.offset(0, -1);
var formula = 'INPUT FORMULA HERE'; // put the formula you want in the adjacentCell here. Don't use it in an arrayformula
// only runs if active cell is in column 2, if the adjacentCell is empty, and if the active cell is not empty(otherwise it runs if you delete something in column 2)
if(col==2 && adjacentCell.getValue()=="" && aCell.getValue()!="") {
adjacentCell1.setValue(formula);
}
}
}
}
Will changing the value not throw out the output of the remaining formulas?
If not, you could set up 2 new tabs: one which will receive the user over-ride values, and another "reflection" tab which you populate with
IF(tabOverride!Rx:Cy, tabOverride!Rx:Cy, tabArray!Rx:Cy)
basically the new tabs are cloned layouts of your array tab, creating an override input layer, plus a presentation layer that uses the IF('override value exists', 'then show override', 'else show array out put') logic to return the desired values.
hope that makes sense!