Good health to all! In this case, the row contains 136 columns, we filter by the 8th column, then we need to copy and paste into another file, for example, columns 134-136. I set the range var rng = sht.getRange(3,134,10000,3), I thought it would be similar to the FILTER() function, but no - the script works only if the range contains a column by which we filter... There was also a decision to insert all 136 columns and delete unnecessary 133, but this is generally, as it seems to me, inhumane.
Can you tell me what needs to be changed in the existing code so that you can copy and paste a filtered range that does not contain the column that is being filtered?
How can the script be modified so that it can be filtered by two or more columns?
Here I found a piece of code that filters the Google table by value and inserts the selected rows into the specified sheet.
I would be grateful for a tip on the optimal solutions for each issue
function CopyPaste()
{//the quantity is written
const SOURCE1 = SpreadsheetApp.openById("Here is the Google table ID");
const sht = SOURCE1.getSheetByName("Sales");
var ss = SpreadsheetApp.getActive();
var sheet2 = ss.getSheetByName("Monitor"); //settings sheet
var diap = sheet2.getRange("A1").getValue(); //value for the filter
var rng = sht.getRange(3,1,10000,136);// filtered range
var PasteSht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet 3');// sheet for inserting data in the current workbook
var rngA = rng.getValues();//this is where a fragment of someone else's code came from (I didn't rename variables)
var yesesA = []
for(var i=0;i<rngA.length;i++)
{
if(rngA[i][7]==diap)
{
yesesA.push(rngA[i])
}
}
var yesesRng = PasteSht.getRange(3, 1, yesesA.length, yesesA[0].length);
yesesRng.setValues(yesesA);
}
Try this
Code.gs
function CopyPaste() { //the quantity is written
const SOURCE1 = SpreadsheetApp.openById("Here is the Google table ID");
const sht = SOURCE1.getSheetByName("Sales");
var ss = SpreadsheetApp.getActive();
var sheet2 = ss.getSheetByName("Monitor"); //settings sheet
var diap = sheet2.getRange("A1").getValue(); //value for the filter
var rng = sht.getDataRange(); // filtered range
var PasteSht = ss.getSheetByName('Sheet 3');// sheet for inserting data in the current workbook
var rngA = rng.getValues();//this is where a fragment of someone else's code came from (I didn't rename variables)
var yesesA = rngA.filter( row => row[7] === diap ); // filter out all rows including diap
ysesA = yesesA.map( row => row.slice(132,136) ); // Array.slice(from,to(not including)) columns 133-136
var yesesRng = PasteSht.getRange(3, 1, yesesA.length, yesesA[0].length);
yesesRng.setValues(yesesA);
}
Reference
Array.filter()
Array.map()
Arrow function expression
I am trying to copy data from 1 spreadsheet to another, I have successfully implemented something i found online that works with a specific range
function cloneGoogleSheet() {
// source doc
var sss = SpreadsheetApp.openById("spreadsheetkey1");
// source sheet
var ss = sss.getSheetByName('_tab_name_source');
// Get full range of data
var SRange = ss.getRange(7,3,5,1);
// get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
// get the data values in range
var SData = SRange.getValues();
// target spreadsheet
var tss = SpreadsheetApp.openById("spreadsheetkey2");
// target sheet
var ts = tss.getSheetByName('tab_name_destination');
// Clear the Google Sheet before copy
//ts.clear({contentsOnly: true});
// set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
};
The above piece coding work perfectly however I need to copy 18 different ranges that i cant just merge into 1 range. I considered the option of using the above however "multiplying" it 18 times for each range that however seems like a very inelegant solution.
I found a working solution that works if it stays within the same spreadsheet since it uses copyto instead of get/set values. The values part works perfectly since it doesnt mess with merge cells formatting. I have been struggling past 2-3 hours in merging the below-working code with elements from the first code to make a working script.
function test () {
try {
var spread = SpreadsheetApp.openById("spreadsheetkey");
var sheet = spread.getSheetByName("tab_name_source");
var rlist = sheet.getRangeList(["c7:c11", "g7:g11", "k7:k11"]);
sheet = spread.getSheetByName("tab_name_destination");
for( var i=0; i<rlist.getRanges().length; i++ ) {
var r1 = rlist.getRanges()[i];
var r2 = sheet.getRange(r1.getA1Notation());
r1.copyto(r2);
}
}
catch(err) {
Logger.log(err);
}
}
I tried initially to adapt the 2nd piece of coding to using setvalues however i had not been able to succesfully implement the part of getvalues within the scope of this code. I figured once I got this piece of code working with get and set values instead of Copyto i would only need to add the spreadsheetid of the other spreadsheet to get the final result
Try this:
function myFunction() {
var sourceSS = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = sourceSS.getSheetByName("sheetname");
var targetSS = SpreadsheetApp.openById("spreadsheet id here");
var targetSheet = targetSS.getSheetByName("Sheet1");
var ranges = ["C7:C11", "G7:G11", "K7:K11"];
ranges.forEach(range => {
var data = sourceSheet.getRange(range).getValues();
targetSheet.getRange(range).setValues(data);
})
}
Source sheet:
Destination sheet:
References:
setValues()
getValues()
Background: My coworkers originally each had a worksheet within the same Google Sheets file that makes a lot of calculations (and was getting unusable). Now, everyone has their own (known) Google Sheets file. To run the same calculations, we need to consolidate all that data into a master sheet (image ref below). We tried =importrange(...), but it's too heavy and breaks often (i.e., Loading... and other unfilled cells).
I've written some code to do this import, but right now its only manual: manually repeating the code and manually add the sheet IDs and changing the destrange.getRange(Cell range) each time. We have 80+ analysts, and fairly high turnover rates, so this would take an absurd amount of time. I'm new to Sheets and Apps Script, and know how to make the script use a cell as reference for a valid range or a valid ID, but I need something that can move a cell down and reference the new info.
Example:
Sheet 1 has a column of everyone Sheet ID
Script Pseudocode
get first row's id(Row 1), get sheet tab, get range, copies to active sheet's corresponding row(Row 1).
gets second row's id(Row 2), get sheet tab, get range, copies to active sheet's corresponding row (Row 2)
etc.
My script understanding is way to low to know how to process this. I have no idea what to read and learn to make it work properly.
function getdata() {
var confirm = Browser.msgBox('Preparing to draw data','Draw the data like your french girls?', Browser.Buttons.YES_NO);
if(confirm == 'yes'){
// I eventually want this to draw the ID from Column A:A, not hard-coded
var sourcess = SpreadsheetApp.openById('1B9sA5J-Jx0kBLuzP5vZ3LZcSw4CN9sS6A_mSbR9b26g');
var sourcesheet = sourcess.getSheetByName('Data Draw'); // source sheet name
var sourcerange = sourcesheet.getRange('E4:DU4'); // range
var sourcevalues = sourcerange.getValues();
var ss = SpreadsheetApp.getActiveSpreadsheet(); //
var destsheet = ss.getSheetByName('Master Totals'); //
// This range needs to somehow move one down after each time it pastes a row in.
var destrange = destsheet.getRange('E4:DU4');
destrange.setValues(sourcevalues); // Data into destsheet
}
}
Any suggestions are greatly appreciated!
Thanks to tehhowch for pointing me in the right direction!
function getdata() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var destsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master Totals');
var confirm = Browser.msgBox('Drawing Data','Would you like to update the sheet? It may take 2 to 5 minutes.', Browser.Buttons.YES_NO);
if(confirm =='yes'){
var lr = ss.getLastRow();
for (var i = 4; i<=lr; i++) {
var currentID = ss.getRange(i, 1).getValue();
var sourcess = SpreadsheetApp.openByUrl(currentID);
var sourcesheet = sourcess.getSheetByName('Data Draw');
var sourcerange = sourcesheet.getRange('E4:DU4');
var sourcevalues = sourcerange.getValues();
var destrange = destsheet.getRange('E' +i+':'+ 'DU'+ i);
destrange.setValues(sourcevalues);
I just had to learn how to use a variable loop.
Edit: thanks also to Phil for making my question more presentable!
Now that you've figured out one way to do it, I'll offer an alternative that uses batch methods (i.e. is much more time- and resource-efficient):
function getData() {
var wb = SpreadsheetApp.getActive();
var ss = wb.getActiveSheet();
var dest = wb.getSheetByName('Master Totals');
if (!dest || "yes" !== Browser.msgBox('Drawing Data', 'Would you like to update the sheet? It may take 2 to 5 minutes.', Browser.Buttons.YES_NO))
return;
// Batch-read the first column into an array of arrays of values.
var ssids = ss.getSheetValues(4, 1, ss.getLastRow() - 4, 1);
var output = [];
for (var row = 0; row < ssids.length; ++row) {
var targetID = ssids[row][0];
// Open the remote sheet (consider using try-catch
// and adding error handling).
var remote = SpreadsheetApp.openById(targetID);
var source = remote.getSheetByName("Data Draw");
var toImport = source.getRange("E4:DU4").getValues();
// Add this 2D array to the end of our 2D output.
output = [].concat(output, toImport);
}
// Write collected data, if any, anchored from E4.
if(output.length > 0 && output[0].length > 0)
dest.getRange(4, 5, output.length, output[0].length).setValues(output);
}
Each call to getRange and setValues adds measurable time to the execution time - i.e. on the order of hundreds of milliseconds. Minimizing use of the Google interface classes and sticking to JavaScript wherever possible will dramatically improve your scripts' responsiveness.
I'm new to Google Apps Script and I'm trying without luck to automate a previously manual process. The script is within a sheet which takes form responses, converts them to a document and then emails the respondent with a copy. Here's the code in question:
function createDocFromSheet(){
var templateid = "1E7zzpvDF0U66aNqJdkUqjONx4wQRarkcWDy28NVqafU"; // get template file id
var folder = DriveApp.getFolderById("1-8lae1z_Z-Sy1IczUyB2JvCqCBV8zB5D")// folder name of where to put completed quotes
// get the data from sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var data = sheet.getRange(2, 1, sheet.getLastRow()-1, sheet.getLastColumn()).getValues();
var username = Session.getActiveUser(); // get their email
var dateNow = new Date(); // get date, clumsily
var dateD = dateNow.getDate();
var dateM = dateNow.getMonth();
var dateY = dateNow.getYear();
// for each row, fill in the template with response data
for (var i in data){
var row = data[i];
// make copy and set active
var docid = DriveApp.getFileById(templateid).makeCopy(row[7]+" - Postal Quote",folder).getId();
var doc = DocumentApp.openById(docid);
var body = doc.getActiveSection();
// date - working
body.replaceText("%D%", dateD);
body.replaceText("%M%", dateM+1);
body.replaceText("%Y%", dateY);
// address - working
body.replaceText("%FNAME%", row[2]);
body.replaceText("%SNAME%", row[3]);
body.replaceText("%ADDL1%", row[4]);
body.replaceText("%ADDL2%", row[5]);
This is setup to trigger on form submit but instead of running the script on the last row it runs for all previous responses as well. This was fine previously when responses were copied to a separate sheet and processed in bulk but I'm lost with how to make it run on only the new response.
Can anyone point me in the right direction?
Line 8; var data = sheet.getRange(2, 1, sheet.getLastRow()-1, sheet.getLastColumn()).getValues(); in this line you are getting the range A2:whatever the last row and column is, that's why it's going over the entire range.
Changing it to var data = sheet.getRange(sheet.getLastRow()-1, 1, 1, sheet.getLastColumn()).getValues(); should work.
or you can use the e parameter of the onFormSubmit event.
var getSubmission = e.range.getValues();
Have a look at the documentation for the e parameter, it's can be difficult to use in the beginning when debugging but it's very useful when you get the hang of it.
I am attempting to write a script that on form submit will send two sets of data to two different spreadsheets. The data is derived from one form. It is supposed to copy the most recent entry and then hide the row to prevent duplication. I am finding that on some occasions it is not hiding the last row and multiple copies are being copied. I realize my script is probably not the most efficient, for example, I could not get a range to work!
The sleep utilities were inserted as I thought there may have been a delay in the writing of the form's input to the spreadsheet and the script was running before this was complete.
The script is attached to the form which writes to a Form Responses sheet, this is then split to a company spreadsheet and a customer spreadsheet. Well that is the intention anyway!
function copyRow(){
Utilities.sleep(2000)
var ss = SpreadsheetApp.openById('1_pnsvWtqB4CUivQZE65nFR0AG9zTOgqBVSlPZW4YCUQ'); //Source Form Input
var sheet = ss.getSheetByName('Responses');
var lastrow = ss.getLastRow();
var rowIdx = sheet.getLastRow();
var rowValues = sheet.getRange(lastrow,1,1,74).getValues();
Logger.log(rowValues);
Utilities.sleep(5000)
var destValues = []; //Data to AUSJET
destValues.push(rowValues[0][0],rowValues[0][1],rowValues[0][2],rowValues[0][3],rowValues[0][4],rowValues[0][5],rowValues[0][6],rowValues[0][7]
,rowValues[0][8],rowValues[0][9],rowValues[0][10],rowValues[0][11],rowValues[0][12],rowValues[0][13],rowValues[0][14],rowValues[0][15]
,rowValues[0][16],rowValues[0][17],rowValues[0][18],rowValues[0][19],rowValues[0][20],rowValues[0][21],rowValues[0][22],rowValues[0][23]
,rowValues[0][24],rowValues[0][25],rowValues[0][26],rowValues[0][27],rowValues[0][28],rowValues[0][29],rowValues[0][30],rowValues[0][31]
,rowValues[0][32],rowValues[0][33],rowValues[0][34],rowValues[0][35],rowValues[0][36],rowValues[0][37],rowValues[0][38],rowValues[0][39]
,rowValues[0][40],rowValues[0][41],rowValues[0][42],rowValues[0][43],rowValues[0][44],rowValues[0][45],rowValues[0][46],rowValues[0][47]
,rowValues[0][48],rowValues[0][49],rowValues[0][50],rowValues[0][51],rowValues[0][52],rowValues[0][53],rowValues[0][54],rowValues[0][55]
,rowValues[0][56],rowValues[0][57],rowValues[0][58],rowValues[0][59],rowValues[0][60],rowValues[0][61],rowValues[0][62],rowValues[0][63]
,rowValues[0][64],rowValues[0][65],rowValues[0][66],rowValues[0][67],rowValues[0][68],rowValues[0][69],rowValues[0][70],rowValues[0][71]
,rowValues[0][73],rowValues[0][74]);
// copy data from col A to col BU
var dest = SpreadsheetApp.openById('1KQ43DJsJY0RpSnFHDcVfgAWLRfLKE6OD28CFkbjpJoU').getSheetByName('Form Responses');[1];
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);
var destValues = []; //DATA to CONCATENATOR
destValues.push(rowValues[0][0],rowValues[0][1],rowValues[0][2],rowValues[0][3],rowValues[0][4],rowValues[0][5],rowValues[0][6],rowValues[0][7]
,rowValues[0][8],rowValues[0][9],rowValues[0][10],rowValues[0][11],rowValues[0][12],rowValues[0][13],rowValues[0][14],rowValues[0][15]
,rowValues[0][16],rowValues[0][17],rowValues[0][18],rowValues[0][19],rowValues[0][20],rowValues[0][21],rowValues[0][22],rowValues[0][23]
,rowValues[0][24],rowValues[0][25],rowValues[0][26],rowValues[0][27],rowValues[0][28],rowValues[0][29],rowValues[0][30],rowValues[0][31]
,rowValues[0][32],rowValues[0][33],rowValues[0][34],rowValues[0][35],rowValues[0][36],rowValues[0][37],rowValues[0][38],rowValues[0][39]
,rowValues[0][40],rowValues[0][41],rowValues[0][42],rowValues[0][43],rowValues[0][44],rowValues[0][45],rowValues[0][46],rowValues[0][47]
,rowValues[0][48],rowValues[0][49],rowValues[0][50],rowValues[0][51],rowValues[0][52],rowValues[0][53],rowValues[0][54],rowValues[0][55]
,rowValues[0][56],rowValues[0][57],rowValues[0][58],rowValues[0][59]);
// copy data from col A to col BH
var dest = SpreadsheetApp.openById('1qB4OnKF3-OXFR1kR3jewHgYeslLdmIiE3maQNx0MPbk').getSheetByName('ROAMES');[1];//
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);
Utilities.sleep(2000)
sheet.hideRows(lastrow)
I am assuming, that as the data is coming from the form so the first column will be 'Timestamp'.
So, I have copied the last row from the source spreadsheet and then compared the value of column A of this last row with the value of column A of the last row of Destination sheet, if both matches then I haven't copied the data...
Only thing that may cause an issue here is if two or more responses are submitted exactly at a same time
Try the following code:
function copyRow(){
Utilities.sleep(2000);
var ss = SpreadsheetApp.openById('1_pnsvWtqB4CUivQZE65nFR0AG9zTOgqBVSlPZW4YCUQ');
var sheet = ss.getSheetByName('Responses');
var lastrow = sheet.getLastRow();
var destValues = sheet.getRange('A'+lastrow+':BU'+lastrow).getValues();
var dest = SpreadsheetApp.openById('1KQ43DJsJY0RpSnFHDcVfgAWLRfLKE6OD28CFkbjpJoU').getSheetByName('Form Responses')
if( dest.getRange(dest.getLastRow(), 1,1,1).getValue().toString() != destValues[0][0].toString() )
dest.getRange(dest.getLastRow()+1,1,1,destValues[0].length).setValues(destValues);
var destValues = sheet.getRange('A'+lastrow+':BH'+lastrow).getValues();
var dest = SpreadsheetApp.openById('1qB4OnKF3-OXFR1kR3jewHgYeslLdmIiE3maQNx0MPbk').getSheetByName('ROAMES')
if( dest.getRange(dest.getLastRow(), 1,1,1).getValue().toString() != destValues[0][0].toString() )
dest.getRange(dest.getLastRow()+1,1,1,destValues[0].length).setValues(destValues);
};