Google Script - Copy dynamic range to new spreadsheet - javascript

I'd appreciate some help on my first google script if possible.
I'm trying to archive our daily processing log by copying and pasting them to the bottom of an end of day log spreadsheet.
The issue is that the number of rows processed each day will vary so I can't set a fixed number of rows to copy to the target spreadsheet.
I just want to copy from row B7 down to the last row with values entered.
function pasteprocessinglog() {
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ss = sss.getSheetByName('Sheet_name');
var range = ss.getRange('B7:J');
var data = range.getValues();
var tss = SpreadsheetApp.openById('URL');
var ts = tss.getSheetByName('Processing Log');
ts.getRange(ts.getLastRow() + 1, 2, ss.getMaxRows(), 9).setValues(data);
}
I'm currently receiving error: Incorrect range height, was 6467 but should be 6473
I'm guessing this is because it's trying to copy the empty rows too and the spreadsheet isn't long enough.
Any help would be appreciated :)
Thank you!

In data retrieved using ss.getRange('B7:J').getValues(), empty cells are included. So the length of retrieved data is larger than that of real data. 6467 and 6473 means the length of data array and the value from getMaxRows(), respectively.
And getMaxRows() retrieves the number of most bottom cell including empty cells. So in the case for using setValues(), data can be copied by using the length of data array for setValues as numRows of getRange (https://developers.google.com/apps-script/reference/spreadsheet/sheet#getRange(Integer,Integer,Integer,Integer)
).
The script is as follows.
function pasteprocessinglog() {
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ss = sss.getSheetByName('Sheet_name');
var firstrow = 7; // 7th row
var range = ss.getRange(firstrow, 2, ss.getLastRow() - firstrow + 1, 9);
var data = range.getValues();
var tss = SpreadsheetApp.openById('URL');
var ts = tss.getSheetByName('Processing Log');
ts.getRange(ts.getLastRow() + 1, 2, data.length, 9).setValues(data);
}
If my understanding have mistaken, I'm sorry.

Related

How To Loop Google Sheet Formula In App Script

I'm trying to set a formula in Google Sheet from Google App Script.
Here's the illustration of the Spreadsheet:
I also tried to make the code but I don't know how to loop it so for every values added to cell range 'A3:F' will automatically SUM it to the Total column (column G). Could you show me how to loop it? Your response will be appreciated :)
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Sheet1');
var cell = s.getRange("G3");
cell.setFormula("=SUM((A3/100)*D3)+((B3/100)*E3)+((C3/100)*F3)");
}
EDIT
Here's the updated code that works for me:
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Sheet1');
const cell = s.getRange(3, 7, s.getLastRow());
cell.setFormula("=SUM((A3/100)*D3)+((B3/100)*E3)+((C3/100)*F3)");
}
Loop is not needed. SetFormula will automatically adjust to a new range, as if autofilled:
const cell = s.getRange(`G3:G${s.getLastRow()}`);
cell.setFormula("=SUM((A3/100)*D3)+((B3/100)*E3)+((C3/100)*F3)");
You can have a "template" for your formula and replace the necessary params with the row number in a loop. Here's an example that sets the formula from row 3 to row 12
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName( 'Sheet1' );
var firstRowNum = 3;
var lastRowNum = 12;
var formulas = [];
var formulaTemplate = '=SUM((A{rowNum}/100)*D{rowNum})+((B{rowNum}/100)*E{rowNum})+((C{rowNum}/100)*F{rowNum})';
for ( var i = firstRowNum; i <= lastRowNum; i++ ) {
formulas.push( [ formulaTemplate.replace( /{rowNum}/g, i ) ] );
}
s.getRange( 'G' + firstRowNum + ':G' + lastRowNum ).setFormulas( formulas );
You can do this with a 'simple' function instead of scripts.
SUMPRODUCT is good but it doesn't loop down. You can use the ARRAYFORMULA, but you'll need to list out each multiplication like A/100*D.
To loop down with ARRAYFORMULA, each column range would be in the format A3:A etc.
Your formula in cell G3 would therefore be:
=ARRAYFORMULA((A3:A/100*D3:D)+(B3:B/100*E3:E)+(C3:C/100*F3:F))
NOTE: row numbers need to be the same as where you've inserted the main ARRAYFORMULA (ie. 3 as per the example). If you get it wrong, your sheet can generate a huge number of rows before you know it!!

How do I extract a specific Column from google sheets using Google Script?

So I have an meal inventory spreadsheet that is fed by a google form. Employees count meals at the end of the day every night and each 2nd cell of each column has a title: Initial, Monday, Tuesday you get the idea. I'd like to notify myself when certain items are sold at a fast rate so that they can be replenished. My problem is that I can easily get data from the most recent night using
.getLastColumn();
but I want to base each lastColumn data from the most recent column that has "Initial" in the second cell of the column and put them in a 2 column array on a seperate sheet. any ideas? this is my script so far;
function activeData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var Sheet = ss.getSheetByName("IREmaildata");
var lastCol = Sheet.getLastColumn();
var rangeInitial = Sheet.getDataRange(); // Not sure if this would be correct?
var initial = rangeInitial.getValues();
var int = "Initial"; //the 3rd cell in "Initial" column must say "Initial".
var rangeLastnight = Sheet.getRange(1,lastCol,37,1); //I can easily get the data from the most recent googleForm submission.
var lastNight = rangeLastnight.getValues(); //I can easily get the data from the most recent googleForm submission.
/*
probably some type of logic will go here?
*/
ss.getSheetByName("Sheet5").getRange(1,2,37,1).setValues(yesterday);
ss.getSheetByName("Sheet5").getRange(1,3,37,1).setValues(today);
}
My Spreadsheet; https://docs.google.com/spreadsheets/d/1X_UcqyXXRMyjZ2j46TymMrIMWvt19HOZTTaEUlIVqwE/edit?usp=sharing
In your shared Spreadsheet, the sheet of IREmaildata and Sheet5 are the input and output you expect, respectively.
From your shared Spreadsheet, you want to retrieve the values from the sheet IREmaildata.
You want to retrieve the last column (Most recent Night Dynamic Column), and retrieve the column (Begining of the week Dynamic Column) which has Initial at the 2nd row and the closest from the last column. And the column "A".
And you want to put the values, which were calculated, to new column (Precenatage sold Static Column).
For your shared Spreadsheet, you want to retrieve the column "A", "V", "Y" and the calculated values to the other sheet in the Spreadsheet.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Flow:
The flow of this sample script is as follows.
Retrieve the values from the data range of the sheet IREmaildata.
Retrieve the index of the last column from the values.
Retrieve the index of the column which has the value of Initial at the row 2.
Retrieve the column "A", the index of the column which has the value of Initial at the row 2, the index of the last column.
Calculate the percentage and put the value to the array for putting to Spreadsheet.
Put the result values to the Spreadsheet.
Sample script:
Please copy and paste the following script to the container-bound script of the shared Spreadsheet. And please prepare the destination sheet and set the destination sheet name to destSheetName, and run the function activeData.
function activeData() {
var destSheetName = "###"; // Please set the destination sheet name.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("IREmaildata");
var values = sheet.getDataRange().getValues();
var lastColumnIndex = values[1].length - 1;
var initialIndex = 0;
for (var i = lastColumnIndex - 1; i >= 0; i--) {
if (values[1][i] == "Initial") {
initialIndex = i;
break;
}
}
var result = values.map(function(row, i) {
var ar = [row[0], row[initialIndex], row[lastColumnIndex]];
if (i == 0) {
ar.push("");
} else if (i == 1) {
ar.push("Since Begining of week");
} else if (i > 1) {
var temp = 1 - (row[lastColumnIndex] / row[initialIndex]);
ar.push(isNaN(temp) ? "None sold" : temp);
}
return ar;
});
var destSheet = ss.getSheetByName(destSheetName);
destSheet.getRange("D3:D").setNumberFormat("0.00%");
destSheet.getRange(1, 1, result.length, result[0].length).setValues(result);
}
Note:
At above script, getValues() is used for retrieving the values from the sheet IREmaildata. In this case, the date values are retrieved as the date object. If you want to fix the date format, for example, please modify var values = sheet.getDataRange().getValues(); to var values = sheet.getDataRange().getDisplayValues();.
References:
map()
setNumberFormat()

How to paste values from one sheet to another to last row of specific column

A novice on app scripts, but managed to successfully build my own script through much research, but now my script is running into errors. Below is my current code:
function MyFunction() {
var sss = SpreadsheetApp.getActive();
var ss = sss.getSheetByName('Daily Sales');
var range = ss.getRange('B8:H83');
var data = range.getValues();
var OUrange = ss.getRange('K8:Q83');
var OUdata = OUrange.getValues();
var ts = sss.getSheetByName('Tracker');
ts.getRange(ts.getLastRow()+1, 1,data.length, data[0].length).setValues(data);
ts.getRange(ts.getLastRow()+1, 1,OUdata.length, OUdata[0].length).setValues(OUdata);
}
In the Daily Sales sheet I am copying values from columns B-H and K-Q and pasting them in the last row of the Tracker sheet starting at Column A. The Daily Sales values in Col. K-Q are pasted correctly below the B-H values, so happy with those results.
On the Tracker sheet these values are in Columns A-G. However I have since added formulas in Columns I and J based on the script data and a manual entry in Column H. These formulas are copied down the entire column within the sheet (i.e. row 5000). Since adding these formulas, the script is now pasting values in A5001.
I realize it is because of these formulas, but is there a way to update my script to paste in the last row of column A while maintaining those formulas in Columns I and J? Thanks in advance.
You could create a helper function that computes the first free row of a given column (NOT a column with formulas)
function MyFunction() {
var sss = SpreadsheetApp.getActive();
var ss = sss.getSheetByName('Daily Sales');
var range = ss.getRange('B8:H83');
var data = range.getValues();
var OUrange = ss.getRange('K8:Q83');
var OUdata = OUrange.getValues();
var ts = sss.getSheetByName('Tracker');
var values = data.concat(OUdata).filter(function (r) {return r[0]});
var fr = findFirstFreeRow(ts, 1) // second parameter represents column to check for first free row
ts.getRange(fr, 1,values.length, values[0].length).setValues(values);
}
function findFirstFreeRow(sheet, colNum) {
var v = sheet.getRange(1, colNum, sheet.getLastRow()).getValues(),
l = v.length,
r;
while (l >= 0) {
if (v[l] && v[l][0].toString().length > 0) {
r = (l + 2);
break;
} else {
l--;
}
}
return r;
}
See if that helps?
After deleting the extra empty rows from your 'Tracker' sheet, you can use the appendRow function to create a new row with the manual values (leaving the cells that need formulas blank).
After the manual values are in, you can then get the cells that need formulas and use setFormula on them.
For the sake of brevity, if you wanted column A,B,C,E,F to have manual values and column D to have a formula you would do:
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow(['A','B','C','','E','F']);
sheet.getRange(sheet.getLastRow(),4).setFormula('=FORMULA(HERE)');

How to Dynamic Paste values after Last Row [Google Script]

I am building a script to copy a row in another spreadsheet. The idea is to have one sheet with the inputs that are going to be stored in a second spreadsheet. However, I am facing some real struggle in building the dynamic paste range. This is the point I was able to reach with my present knowledge:
function Export() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var database = SpreadsheetApp.openById("xxx");
var source = ss.getSheetByName('yyy');
var dataToCopy = source.getRange('bb').getValues();
var copyToSheet = database.getSheetByName("zzz");
var copyData = copyToSheet.getRange('bb').setValues(dataToCopy)
var Clean = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('yyy').getRange('bb');
Clean.clear({contentsOnly:true});
}
This script copy a range into a fixed range in a second spreadsheet, and it clears the values present in the source. My question is: How can I create a range that makes the script paste the data in the first blank row in the second spreadsheet?
I tried some combination of appendRow, getLastRow, insertRowAfter, but I was not able to get it done.
Thank you for your time!
This is what I was able to achieve with the help of a friend:
function Export2() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var database = SpreadsheetApp.openById("1UfKqXCMNIbjh3ge7s26SNkXyGez-bY3fvl6_3-RQKos");
var source = ss.getSheetByName('Sheet26');
var dataToCopy = source.getRange('A1:E1');
var copyToSheet = database.getSheetByName("TOT");
var lastRow = copyToSheet.getLastRow();
for (var i = 1; i<6 ;i++){
var Paste = copyToSheet.getRange(lastRow + 1,i).setValue(dataToCopy.getCell(1, i).getValue());
}
var Clean = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet26').getRange('A1:E1');
Clean.clear({contentsOnly:true});
}
Below is a script that will do the thing you want to do dynamically without the use of named ranges. It assumes that all the data on the source sheet should be copied over to the destination sheet. Let me know if you need any additional explanation beyond what is provided in the comments.
function Export() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var database = SpreadsheetApp.openById("xxx");
var source = ss.getSheetByName('yyy');
var dataToCopyRng = source.getDataRange(); //Gets range object of all data on source sheet
var dataToCopy = dataToCopyRng.getValues(); //Gets the values of the source range in a 2 dimensional array
var copyToSheet = database.getSheetByName("zzz");
var copyData = copyToSheet.getRange(copyToSheet.getLastRow()+1,1,dataToCopy.length,dataToCopy[0].length).setValues(dataToCopy)
//Explination of the above command is as follows getRange(row, column, numRows, numColumns)
//--row is copyToSheet.getLastRow()+1 -- finds last row with content and adds one
//--Column is 1 for Column A
//--numRows is the length of the array (how many rows are in the array of values)
//--numcolumns is the length of the first element of the 2 dimensional array (arrays start at zero). The length of the first element is how many columns are in the array
//--combine the above with .getRange and you get the range object that is an exact match to the array of source data rows and columns
//--then you simply set the values of this range with the source data
dataToCopyRng.clear({contentsOnly:true});
}
You can learn more about 2 dimensional arrays here.
Cheers!

How do I copy a range from one Google Sheet to another when edits are made?

I have a sheet that will update based on new articles in an RSS feed using importfeed() and the URLs are analyzed with importxml(). Problem is the data is always changing and I would like to archive old data from the importfeed() function. I'd just like to move the most updated data from one sheet to another without overwriting anything.
Here is the sample code from: https://stackoverflow.com/users/650206/jeremy:
function myFunction() {
// Get Spreadsheets
var source = SpreadsheetApp.openById("spreadsheetKeySource");
var target = SpreadsheetApp.openById("spreadsheetKeyTarget");
// Set Sheets
var source_sheet = source.getSheetByName("Sheet1");
var target_sheet = target.getSheetByName("Sheet1");
// Get target last row
var last_row = target_sheet.getLastRow();
// Set Ranges
var source_range = source_sheet.getRange("A1:B1");
var target_range = target_sheet.getRange("A"+(last_row+1)+":B"+(last_row+1));
// Fetch values
var values = source_range.getValues();
// Save to spreadsheet
target_range.setValues(values);
}
Problem with the above code is it only selects one row when I need it to select an entire range (e.g. A1:G55) and paste that data below the old data in another sheet.
Any help would be much appreciated!
EDIT
The error I'm getting when I change:
var source_range = source_sheet.getRange("A1:B1");
var target_range = target_sheet.getRange("A"+(last_row+1)+":B"+(last_row+1));
to:
var source_range = source_sheet.getRange("A1:G25");
var target_range = target_sheet.getRange("A"+(last_row+1)+":G"+(last_row+1));
is "Incorrect range height, was 5 but should be 1 (line 21, file "Code")"
which is this piece of code:
target_range.setValues(values);
var source_range = source_sheet.getRange("A1:G25");
var target_range = target_sheet.getRange("A"+(last_row+1)+":G"+(last_row+1));
The lines above attempt to copy 25 rows of data and paste that into one row. I'm surprised that the error message says "was 5 but should be 1". I'd have expected it to say "was 25 but should be 1".
Try this instead:
var source_range = source_sheet.getRange("A1:G25");
var target_range = target_sheet.getRange("A"+(last_row+1)+":G"+(last_row+25));

Categories

Resources