Google Script how to back up new rows to a master spreadsheet - google-apps-script

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);
}

Related

Cell that contains an hour change when I paste it to a new sheet

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)));

transferring data from one sheet to another one with script [duplicate]

sure I had this down but just can't get it right. Had a script set up to get data from one sheet and put it into another one, which I have done but it leaves gaps when copying and I can't figure out how to solve it. I'm sure in the code, its where I have put a question mark, is where the problem lies.
I have tried put i, last, last+1, 10, 12 but none of these work, feel like i'm missing something small to get this right. Below is the code a link to view the sheet if needed (the sheet is just for me to learn from, a basic example if you will).
Thanks in advance and also if the code could be better written, please just let me know as still learning this :)
function copyInfo() {
var app = SpreadsheetApp;
var copySheet = app.getActiveSpreadsheet().getSheetByName("Copy");
for (var i = 2; i <12; i++) {
var getInfo = copySheet.getRange(2,2,i,2).getValues();
// get the info from range above - start at row 2 on column 2 (b), get number of rows i , number of columns = 2, b,c
var last = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Paste").getLastRow();
var pasteSheet = app.getActiveSpreadsheet().getSheetByName("Paste");
// Tell it where you want the info to go to
pasteSheet.getRange(last+1,1,?,2).setValues(getInfo);
var clearIt = copySheet.getRange(2,2,i,2).clearContent();
// this clears the copy range aka getInfo
}}
link to sheet
You can copy whole range at once using copyTo, so your function could be rewritten as:
function copyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
// get source range
var source = copySheet.getRange(2,2,12,2);
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,2,12,2);
// copy values to destination range
source.copyTo(destination);
// clear source values
source.clearContent();
}

Auto-archiving data in Google Sheets

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 .

Improving Apps Script flexibility by using a column of sheet data instead of hard-coded IDs

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.

Copy a row with specific cells to another spreadsheet

I have been searching for a way to copy certain cells from a row and paste them into another spreadsheet, but all I can seem to find are ways to do that just from sheet to sheet within one spreadsheet or questions that deal with code way above my head. I'm just now learning to code in Google Spreadsheets and I can't seem to get it right. Here is my code for now, I'm working on just copying one cell first and after I can do that I'll get a loop to iterate through the row and pick the cells I want to copy.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var master = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c');
var target = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c');
var master_sheet = master.getSheetByName("Steve2");
var target_sheet = target.getSheetByName("Corbin1");
var master_range = master_sheet.getRange("A1");
var target_range = target_sheet.getRange("A1");
master_range.copyTo(target_range);
Right now it is giving me an error saying that it cannot call the getRange method of null. I'm not sure if I'm using OpenById correctly or if I can even use that in this situation.
OK I've got it working now. It copies the row perfectly and it copies only the cells I want. Now I need help with the pasting part. It copies everything fine and puts it into the other sheet great, but I need it to copy into the next available row and into the first available columns. So if row 5 is the last column of data, I need it to paste into row 6 and take up the first 6 or so columns.
This is what I have so far.
function menuItem1() {
var sss = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c'); // sss = source spreadsheet Steve2
var ss = sss.getSheetByName('Sheet1'); // ss = source sheet
//Message box asking user to specify the row to be copied
var answer = Browser.inputBox('What row would you like to copy?');
var range = parseInt(answer);
var array = [1,2,3,9,12,30];
//Runs a loop to iterate through array, using array elements as column numbers
for(var i = 0; i < array.length; i++){
var SRange = ss.getRange(answer,1,1,array[i]);
//get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
//get the data values in range
var SData = SRange.getValues();
}
var tss = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c'); // tss = target spreadsheet Corbin1
var ts = tss.getSheetByName('Sheet1'); // ts = target sheet
//set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
//Confirmation message that the row was copied
Browser.msgBox('You have successfully copied Row: ' + answer);
}
You are getting this error maybe because your spreadsheet does not have a sheet called Steve2 or Cobin1. Try using the method master.getSheets()[0], this way you will get the first sheet without using their name.
You can algo use this piece of code to check the sheets names:
for(var x in master.getSheets()) {
Logger.log(master.getSheets()[x].getSheetName());
}
best,