I'm fairly new to apps script and writing script entirely, however, I've dabbled a bit. For a little bit of context on my ask, my team meets weekly and use a google sheet to manage department updates. I'd like to have this sheet archived so that we can clear each week.
Problem: I want to copy a sheet into another workbook weekly. The intent is to create an archive.
function cloneGoogleSheet(ssA, ssB) {
// source doc
var sss = SpreadsheetApp.openById('10ui5vIJkE0z-DVZ8ywJPLscrhZ84u5SSBchUN-BsbE0');
// source sheet
var ss = sss.getSheetByName('NEW Department Updates');
// Get full range of data
var SRange = ss.getDataRange();
// 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('1TP6HqfZSLAKLco2hTfyrsCzYUW76KY0zEZDzoaeI7CA');
// target sheet
var ts = tss.getSheetByName('Department Updates');
// 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);
};
Request: How can I add in language around appending rows? Thanks in advance for your help!
I think there is maybe a quicker way to do it if it's what your looking for
var ssA = SpreadsheetApp.openById('10ui5vIJkE0z-DVZ8ywJPLscrhZ84u5SSBchUN-BsbE0');
var sheetA = ssA.getSheetByName('NEW Department Updates');
var dataToMove = sheetA.getRange(1,1,sheetA.getLastRow(),sheetA.getLastColumn()).getValues();
var ssB = SpreadsheetApp.openById('1TP6HqfZSLAKLco2hTfyrsCzYUW76KY0zEZDzoaeI7CA');
var sheetB = ssB.getSheetByName('Department Updates');
dataToMove.forEach(function(elts){
sheetB.appendRow(elts)
});
sheetA.deleteRows(1,sheetA.getLastRow());
I hope I've answered at what you're looking for .
Related
I'm using this simple script to paste data into a new spreadsheet.
In column C I have an hour in this format 05:00:00
When the script pastes the value, this hour changes! I can't understand why.
Is it about a time zone somewhere?
Thanks
j.
function copyDataToArchive() {
var sss = SpreadsheetApp.getActiveSpreadsheet();; // sss = source spreadsheet
var ss = sss.getSheetByName("1. Dispatching"); // ss = source sheet
//Get full range of data
var sRange = ss.getRange('a6:l80');
//get A1 notation identifying the range
//var A1Range = SRange.getA1Notation();
//get the data values in range
var sData = sRange.getValues();
var tss = SpreadsheetApp.openById("IDPasteSheet"); // tss = target spreadsheet
var ts = tss.getSheetByName("ARCHIVAGE"); // ts = target sheet
ts.getRange("a"+(getLastDataRowArchivage(ts)+1)+":l"+(getLastDataRowArchivage(ts)+75)).setValues(sData);
A solution was found in the comments but for future reference I'd like to add an explanation of why this happened.
When copying values, getValues() gets just the raw data within the cell without taking into account the format. Then when you use setValues(), by default the format in previously unused cells is set to "Automatic", so Sheets will just guess the format based on the values and adjust accordingly. With dates/times this can cause issues.
getDisplayValues() works because it takes into account the formatting to read exactly what's displayed and turn it into a String. Sheets is better at parsing this since it's closer to what users normally paste. I guess it does something like "prioritizing" the intended display value.
Maybe there would be some fringe scenarios where a string would not work, so I would recommend you use copyTo() instead if you plan to use the values in the range the same way and keep the formatting, since that's what the method is designed to do. In your case it probably would look like this:
function copyDataToArchive() {
var sss = SpreadsheetApp.getActiveSpreadsheet();; // sss = source spreadsheet
var ss = sss.getSheetByName("1. Dispatching"); // ss = source sheet
var sRange = ss.getRange('a6:l80');
var tss = SpreadsheetApp.openById("IDPasteSheet"); // tss = target spreadsheet
var ts = tss.getSheetByName("ARCHIVAGE"); // ts = target sheet
sRange.CopyTo(ts.getRange("a"+(getLastDataRowArchivage(ts)+1)+":l"+(getLastDataRowArchivage(ts)+75)));
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()
So the gist of my project is to copy new data added to spreadsheet A to spreadsheet B. The intention is to use spreadsheet A as an input method and spreadsheet B as a log of all data input into A from all of time. A master sheet so to speak. Note that this will be run on a time-based trigger and all data from sheet a will be deleted.
I've taken some code from Stackoverflow (thank you to who made it) and made some changes. I'm able to copy over the first set of data from A to B but when I delete the data from A, add new data and run the code I lose all I've input in B. I may as well have use =importrange.
My solution was logical and to take the getLastRow of B and put this before setting setValues. Theoretically, this should get the last row of B and input the new data from A into the last row of B. Easy right, NO, I've been trying to figure this out for days and many hours reading similar cases but I'm not able to get past this hurdle.
I'm speculating that I've misunderstood something in my variable SRange, A1Range or SData.
Any help would be super helpful.
function CopyDataToNewSheet() {
var sss = SpreadsheetApp.openById('XXXXXXXXXXXXXXXXXXXXX');
var ss = sss.getSheetByName('Sheet1');
var lr = ss.getLastRow();
var lc = ss.getLastColumn();
var SRange = ss.getRange(2,1,lr,lc);
var A1Range = SRange.getA1Notation();
var SData = SRange.getValues();
var tss = SpreadsheetApp.openById('XXXXXXXXXXXXXXXXXXXXX');
var ts = tss.getSheetByName('Sheet1');
var tlr = ts.getLastRow()+1;
Logger.log(tlr);
tlr.getRange(A1Range).setValues(SData);
}
function CopyDataToNewSheet() {
var ss=SpreadsheetApp.openById('XXXXXXXXXXXXXXXXXXXXX');
var sh=ss.getSheetByName('Sheet1');
var srg=sh.getRange(2,1,sh.getLastRow()-1,sh.getLastColumn());
var dA=srg.getValues();
var tss=SpreadsheetApp.openById('XXXXXXXXXXXXXXXXXXXXX');
var tsh=tss.getSheetByName('Sheet1');
tsh.getRange(tsh.getLastRow()+1,1,dA.length,dA[0].length).setValues(dA);
}
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.
At the moment this is the function I'm using but I have no way of testing if it will work in the spreadsheet until I publish the application.
function readSelection() {
//The commented lines aren't needed if the sheet is open already
//var sheetid = "sheet id here";
//var spreadsheet = SpreadsheetApp.openById(sheetid);
//SpreadsheetApp.setActiveSpreadsheet(spreadsheet);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
//sheet.setActiveSelection("B2:B22");
var activerange = sheet.getActiveRange();
var activecells = activerange.getValues();
return activecells;
};
I assume you mean highlighted == selected
The result depends on whether the cells are contiguous or not (non contiguous cell selection is available in the new spreadsheets features http://googleblog.blogspot.co.nz/2013/12/new-google-sheets-faster-more-powerful.html
For contiguous cells selected your code returns the values of the selection as an array, for non-contiguous cells your code will return the an array with the single value of the LAST selected item.
I suggest that this is a bug in the implementation of the new spreadsheet. If it is important to you, I suggest you raise an issue. For the old spreadsheets, you can only select contiguous cells (eg B2:B22) so it will work as you expect.
The easiest way to answer this Q is to run the code you have written! You don't have to publish anything just run the code in the script editor of the spreadsheet you are examining
and look at the log.
function readSelection() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var activerange = sheet.getActiveRange();
var activecells = activerange.getValues();
Logger.log(activecells)
return
};
There is no way to do this at the moment or to obtain the selected ranges from a script.
A request is pending and you can support it here : https://code.google.com/p/google-apps-script-issues/issues/detail?id=4056
by adding a star to the request.
If/when this function is implemented your code would look as follows:
function readSelection() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var activeranges = sheet.getSelectedRanges();
var activecells = [] ;'
for (var ar in activeranges)
activecells = activecells.concat(activeranges[ar].getValues()) ;
Logger.log(activecells)
return ;
}
note that selected ranges may overlap, so some cell contents could be added twice.