Very simple question.
How do you make endless row on spreadsheet? Like Excel.
I have this problem when I use google sheet to scan barcodes.
When rows reached 1000, I need to add more manually.
But sometimes I forget, then I keep scanning.
After that I check my sheet, I missed a lot of input but I don't remember which barcode was the last one, so I have to do them all over again after increasing the rows.
If google sheets has the infinite rows like Excel, I won't have to worry about it no more.
Do you guys have any solutions on this?
Use Apps Script to Make Your Sheet Dynamic
With Apps Script, you can write a function to detect how many cells are between the data inserted and the end of the spreadsheet, and add rows if they are too close.
function addRowsIfCloseToEnd() {
let file = SpreadsheetApp.getActive();
// INPUT YOUR SHEET NAME HERE
let sheet = file.getSheetByName("Sheet1");
let maxRow = sheet.getMaxRows()
let lastRow = sheet.getLastRow()
// In this example, when the values are 100 rows
// from the end of the sheet, it will add 100 rows
// to the end. Change this to your liking.
if (maxRow - lastRow < 100) {
sheet.insertRowsAfter(maxRow, 100)
}
}
In this example, the function checks when values are less than 100 rows from the end of the spreadsheet, and if it is, it will add 100 extra rows to the sheet.
You should adjust these numbers to suit your workflow, I don't know how many bar codes you scan or how quickly.
You have two options for how to trigger this:
onEdit
This is a simple trigger designed to run a function every single time there is an edit on the sheet. You can call the previous function like this:
function onEdit() {
addRowsIfCloseToEnd()
}
If you have authorized your script, then this should run every time you make an edit:
In this example I only add 10 rows every time, to demonstrate.
Time-based trigger
Depending on how many barcodes you scan and how quickly, you may not want this function to run every single time you scan a barcode, in which case you can make a trigger to run every 5 minutes for example:
function createClockTrigger() {
ScriptApp.newTrigger("addRowsIfCloseToEnd")
.timeBased()
.everyMinutes(5)
.create();
}
References
Apps Script
Tutorials
Simple Triggers
onEdit
ClockTriggerBuilder
Related
I have a spreadsheet where some columns are progressively merged to represent the balance of a period. Roughly like this:
(don't mind the actual values, these are random just to illustrate)
It is easy enough to just use simple formulas to refer to the ranges to the left when you are looking at them and know, for instance, that this week is C16:C22, next week is C23:C29 and so on. Weeks are relatively simple as they are regular, but months are a bit more complex, yet still just as doable. It is toilsome, though.
What I would really like to do though, would be to just get the size of the merged cell, for instance, if there was a way to write a formula like CELL('rows') that would tell me how many rows it occupies.
Unfortunately I've only managed to find a ROW() formula function that only tells the first row of the current (merged) cell, and a ROWS() that requires that I pass it a range, which is what I'm trying to obtain in the first place. Once I have the cell size in rows, I can infer its data range to the left and won't have to manually edit the formulae for each week and month. Even if I still need to do the merging, that will save a ton of work.
I would prefer to stick with formulae only, but if the solution lies in a script, so be it.
counting merged cells is possible only with script.
but there is an alternative... for week count you can use:
=ARRAYFORMULA(IF(A2:A="";;ISOWEEKNUM(A2:A)))
then to turn it into a count like:
=ARRAYFORMULA(IF(A2:A="";;COUNTIFS(
ISOWEEKNUM(A2:A); ISOWEEKNUM(A2:A); ROW(A2:A); "<="&ROW(A2:A))))
respectively for a month, you can do:
=ARRAYFORMULA(IF(A2:A="";;MONTH(A2:A)))
I could not get the desired results with a formula like #player0 but as an alternative, you can also try this script.
Once you run the script, it will write on column F the number of rows and the range of the merged cells from column E. You can change ranges in the script to test it with other columns that have merged cells.
function numRows(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Página1");
var range = sheet.getRange("E2:E")
if( range.isPartOfMerge() ) {
var range = range.getMergedRanges();
for (i=0; i<range.length;i++){
var numRows = range[i].getNumRows();
var ranRows = range[i].getA1Notation();
var lastRow = range[i].getLastRow();
Logger.log("Number of rows in range "+ ranRows + " is: " + numRows)
sheet.getRange("F"+lastRow).setValue("Range: "+ranRows+"\n"+ "NumRows: "+numRows)
}
}
else {
}
}
Let me know if you have any questions.
I have little to no coding knowledge, so apologies if the solution is too obvious!
I am trying to add a Last Modified column to a Google Sheets file. To do this, I am using an AppScript function with the following code:
function setTimestamp(x) {
if(x != ""){
return new Date();
}
}
This works fine when I use setTimestamp(x) in my file. However, I am combining this with a Zapier action that creates a new row whenever new media is added. Every time a new row is created, any existing formulas are removed.
I assume I need to use ARRAYFORMULA to apply the setTimestamp formula to newly-created rows, but it must only apply to rows that aren't blank.
I have tried the following:
={"Last Modified";ARRAYFORMULA(setTimestamp(A2:A))} -> Only worked on first row
={"Last Modified";ARRAYFORMULA(B2:B=setTimestamp(A2:A))} -> Broke the file
={"Last Modified";ARRAYFORMULA(IF(A2:A)=1,setTimestamp(A2:A),"")} -> Expected 1 argument, got 3
Is there a way I can combine the IF into the script or a better way to solve the problem?
A public version of my file is available here: https://docs.google.com/spreadsheets/d/13zkVRPr2Wh5bHjCT8cenInHnBk7qkMkuEMdwUxC_cRU/edit?usp=sharing
All data is dummy data and stock photos.
Unfortunately, arrayformula does not function as an array map function for custom functions. (Even for native functions where you may expect it to work that way, it does not always, sadly.)
To handle array range, we need the custom function to handle array range directly. That also limits the number of individual calls to custom functions, which materially saves execution time.
To handle array range, there are 2 ways. I'll comment on both.
Array range directly as input of custom function
If the input is a single cell, it is read directly
If the input range spans more than a single cell, the data is read as nested lists: a list of lists of rows.
For example, A1 will be read as the data in A1. A1:B2 will be read as [[A1, B1], [A2, B2]].
You can remember it as columns of rows.
As for the input data format, numbers are taken without the display format. Texts are taken as strings.
If output is an array range, the result will automatically expend.
Thus, in your example, in B2 you can almost do
=setTimestamp(A2:A)
where setTimestamp() has been modified to
function out = setTimestamp(arr) {
out=Array(mat.length);
for (i=0;i<mat.length;i++){
j=0
if(arr[i][j] != ""){
out[i]=new Date();
}
}
return out
}
For more details, see the official help page. (Over the years, more details have become available.)
Almost, but not quite. For your direct question, above provides the answer. However, you seem to have an implicit requirement that your custom function is executed every time a new URL is found. Be careful that what happens here is that every time Google Sheet updates cell content, a new Date() is created and outputted.
Array range read within custom function
Since you know your URLs are in A2:A, and you want the output of your custom function to be B2:B, you can read and modify those ranges directly within your custom function via the Range Class.
In this route, you may find getLastRow(), getLastColumn() in Sheet and getNextDataCell() in Range convenient.
When you need to execute your custom function, you can run it manually or add onEdit() trigger to your custom function. (But onEdit() itself can mean substantial UI lag when using the sheet. It's usually more appropriate for sheets that parse external data automatically. See other triggers in the link for motions.)
In your example, you can almost do
function setTimestamp() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var lastRow = sheet.getLastRow();
var row=1;
var cell = sheet.getRange(row,1).getValue();
while (row<=lastRow) {
if(cell.getValue() != ""){
sheet.getRange(row,2).setValue(new Date());
}
cell = sheet.getRange(row,1,lastRow).getNextDataCell(SpreadsheetApp.Direction.DOWN);
row=cell.getRow();
}
}
which will scan for all URLs in A2:A and write current time to B2:B when executed.
Again, your example implicitly points to updating only when a new URL is found. So be careful about that. Use triggers as needed.
As for the need to place formula in B1, you can (and should) reference the output of your other application in a different sheet so that you or a different application of yours can edit without conflict.
Thus, for what was asked, we have everything.
I am not familiar with google sheets or excel, so I'm not even sure if what I want to do is possible.
I have one thousand rows in a google sheets document. I need a column that has a number to represent the row. Starting at an arbitrary row (lets say row 5 in the document), That cell value needs to be 1. The next row needs that column value to be 2. Then 3, 4, 5, 6... all the way to 1000. It's not feasible to do that manually, so is there a way to automatically fill in the cells with the values I need?
This next part is what I can't figure out. I've found a few solutions to the first part, but none that work with this extra condition. After I generate these numbers, I need to reorder the rows (reordering can't be done before). The problem is that if I use some formula in google sheets, as soon as I generate the numbers then reorder the rows, the formula either breaks or recalculates the numbers, setting them back to 1, 2, 3..., when (for example) after the reorder I would expect 42, 815, 934...
Is what I want to do possible, and if so how can I accomplish this?
Besides the solution that has already been provided, you can also make use of Apps Script and write your own script in order to change the cell values.
Some methods which can be of help to you are:
getRange() - in order to retrieve the range from the sheet;
setValue() - in order to set the value of the cell/s;
Thererefore, your script will end up something similar to:
function setCellValues() {
let spreadsheet = SpreadsheetApp.openById("SS_ID");
let sheet = spreadsheet.getSheetByName("SHEET_NAME");
let startRow = "START_ROW";
let startCol = "START_COL";
for (let i = 0; i < 1000; i++) {
sheet.getRange("START_ROW" + i, "START_COL").setValue(i + 1);
}
}
As for reordering the rows, you can use Apps Script for this again or a simple SORT function.
Reference
Apps Script Sheet Class - getRange();
Apps Script Range Class - setValue();
SORT function.
I am using Zapier to insert external content into a Google Spreadsheet tab automatically and it appears to insert a row directly under the last non-empty row rather than replacing the content in the next empty row.
So if row 7 was the last row, Zapier inserts a new row under 7 and the old row 8 becomes row 9.
I then have two other tabs, both viewable on the web (where the first isn't) that reference the content in the first tab but as new content is added, these references in the format of data!a8 also gets moved. If I use data!$a$8 then I have to change 500 rows manually.
With or without coding, is there a way to allow Zapier to insert the rows but still reference that row automatically?
For those attempting to do this without script, it appears it is not possible.
Script
Create a function like the one below. Note we are reading one sheet (AutomaticImport) and writing to the sheet WebData
function fncUpdateWebData() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheet = ss.getSheetByName("AutomaticImport"),
sheetWeb = ss.getSheetByName("WebData"),
arrRides = sheet.getDataRange().getValues(),
row,col,iOutputRow,strURL;
iOutputRow = 2;
for ( iRow = 1; iRow < arrRides.length; iRow++) {
sheetWeb.getRange(iOutputRow,1).setValue(arrRides[iRow][5]); // date
strURL = '=HYPERLINK("' + 'https://www.strava.com/activities/' + arrRides[iRow][7] + '","' + arrRides[iRow][8] + '")';
sheetWeb.getRange(iOutputRow,2).setValue(strURL); // start & link
sheetWeb.getRange(iOutputRow,3).setValue(arrRides[iRow][4]); // Distance
sheetWeb.getRange(iOutputRow,4).setValue(arrRides[iRow][0]); // Avg Speed
iOutputRow++;
}
}
In Resources/Current Project Triggers and a new trigger and use your new function name, "from Spreadsheet" and select "onChange"
I hope his helps get you over the hurdle.
I know this is a really, really late answer, but I was having the same issue and almost used the accepted solution before realizing there's a much better and easier way.
It's actually in the Zapier docs, right here. The solution is to create two Google Sheets, one for Zapier and the other for your formulas. Hook Zapier up to the first sheet, and then use the IMPORTRANGE command to copy the necessary columns into the second sheet. Write your formulas in the second sheet, and you'll notice that the extra layer of indirection stops Google from rewriting them when a row is added to the source range!
Tl;dr: RTFM, as usual.
I saw several complains about the delay of updating data through IMPORTRANGE in Google Sheets but I need the opposite and don't want the second sheet to get updated automatically, just update at the end of the day for example.
The code is already like this:
=IMPORTRANGE("The Key","The_Page!B:D")
I hacked around this by, on both spreadsheets by creating a refresh loop using a NOW cell, with both spreadsheets crossreferencing each other's NOW cell.
When the original sheet gets appended with a form submission or something, it updates its own NOW cell, and reupdates own IMPORTRANGE cell. The second spreadsheet follows suit, updating its own NOW cell to provide the original sheet with the correct data. Because the second spreadsheet has updated itself, it also updates the main IMPORTRANGE which refreshes the data you want it to display in the first place, as well as the IMPORTRANGE cell which gets the NOW cell from the original spreadsheet
At least, I'm pretty sure that's how it works. All I know, and all I care about, frankly, is that it works
Maybe you need to use the script editor and write a simple function of the kind:
function importData()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(); //source ss
var sheet = ss.getSheetByName("The_Page"); //opens the sheet with your source data
var values = sheet.getRange("B:D").getValues(); //gets needed values
var ts = SpreadsheetApp.openById("The Key"); //target ss - paste your key
ts.getSheetByName("Name of the target sheet").getRange("B:D").setValues(values);
}
And then add a time-driven trigger to this project (Resources > Current project's triggers > Add a new one).