I have found a few options that come close to what I want to do, but nothing matching it exactly.
The request is simple enough.
"Sheet A" - Master Sheet (has 1 header row)
"Sheet B" - Input Sheet (has 1 header row)
"Column C" - Unique ID (same column on both sheets)
Trigger
Sheet B is edited
Actions
Script finds the Unique ID from Sheet B in Column C and looks for it in Sheet A in Column C.
If it finds it, the entire respective row on Sheet A is replaced with the entire respective row from Sheet B.
If it does not find it, a new row is added at the bottom of Sheet A and the entire respective row from Sheet B is added as a new record into the new row at the bottom of Sheet A.
The entire respective row on Sheet B is Deleted.
Actions repeat until there are no populated rows in Sheet B from row 2 on (i.e. excluding the row 1 header).
Thanks
Edits
For clarification on why I am looking to do this. I have a Form that is being submitted and sending the data through to Google Sheets (Cognito -> Zapier -> Google Sheets). Part of this form involves repeating sections (line items). The current method that is importing the responses has no issue with adding new responses correctly, however when a response is updated, it cannot find/update the existing row(s) correctly for the repeating sections. So I had the intention of using Sheet A as my master sheet and then using Sheet B to simply be a receiving sheet. This way I can just submit every entry (including updated ones) as a "new" entry on Sheet B, and then have my script do the updating.
Sheet B will be edited automatically every time a new form entry is submitted or updated. The "edit" is basically a new row being added and data being populated into that row. It may be a good idea to add a 1 minute timer to the trigger so that if there is lots of data being added that it gives time for that to happen.
I am not even remotely close to a script expert. I just browse around different scripts other people have made and try to combine them to get them to work for what I need. I have found scripts that will move a row over and then delete it, but it does not check for matching values to update. I have found other scripts that check for unique values and copy over, but they do not delete the original row on the other sheet. I have tried to combine them, but since I don't have the base knowledge, I can't seem to get it to work.
As a workaround I'd use the onEdit simple trigger and a O(n) search
Here's my approach:
function onEdit(e) {
// If it's not the Sheet B it won't make changes
if (e.range.getSheet().getName() !== "Sheet B") {
return;
}
var range = e.range;
var numberRow = range.getA1Notation().slice(1);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetA = ss.getSheetByName("Sheet A");
var sheetB = ss.getSheetByName("Sheet B");
var currentRowB = sheetB.getRange(`A${numberRow}:D${numberRow}`);
var id = currentRowB.getValues()[0][2];
// There's to be 4 values in the row (no empty values)
if(currentRowB.getValues()[0].filter(value => value !== '').length === 4) {
// Get all the values in Sheet A
var rows = sheetA.getDataRange().getValues();
for (row=1; row < rows.length; row++) {
// If column C matches the ID replace the row
if(rows[row][2] === id) {
var currentRowA = sheetA.getRange(`A${row+1}:D${row+1}`);
currentRowA.setValues(currentRowB.getValues());
currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
return;
}
}
// If the ID doesn't match then insert a new row
var newRow = sheetA.getRange(`A${rows.length+1}:D${rows.length+1}`);
newRow.setValues(currentRowB.getValues());
currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
}
}
Which meets the requirements you asked:
Script finds the Unique ID from Sheet B in Column C and looks for it in Sheet A in Column C. (line 19-28)
If it finds it, the entire respective row on Sheet A is replaced with the entire respective row from Sheet B. (line 22-24)
If it does not find it, a new row is added at the bottom of Sheet A and the entire respective row from Sheet B is added as a new record into the new row at the bottom of Sheet A. (line 31-33)
The entire respective row on Sheet B is Deleted. (line 22 and 33)
I used this Sheet format as example:
Both Sheets have the same format. Keep in mind that this script checks if there's a valid row (in this specific case 4 columns which compose a row) before replacing it.
As a different approach (handling blank data)
In a summary this script should run every X minutes or the time you want it doesn't matter if there's new data incoming because this code will handle all the data given a certain time.
I edited the code in order to use the Z1 cell as a blocker cell and a time based trigger:
Trigger:
Code
function processCells() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetA = ss.getSheetByName("Sheet A");
var sheetB = ss.getSheetByName("Sheet B");
// If it's not the Sheet B or if there's a process running it won't make changes
if (sheetB.getName() !== "Sheet B" || sheetB.getRange("Z1") === "Running") {
return;
}
// Use the Z1 cell in order to block or unblock this sheet
sheetB.getRange("Z1").setValue('Running');
// Process all the rows
var numCells = sheetB.getDataRange().getValues().length + 1;
for (numberRow = 2; numberRow <= numCells; numberRow++) {
var currentRowB = sheetB.getRange(`A${numberRow}:D${numberRow}`);
var id = currentRowB.getValues()[0][2];
// Get all the values in Sheet A
var rows = sheetA.getDataRange().getValues();
var match = false;
for (row=1; row < rows.length; row++) {
// If column C matches the ID replace the row
if(rows[row][2] === id) {
var currentRowA = sheetA.getRange(`A${row+1}:D${row+1}`);
currentRowA.setValues(currentRowB.getValues());
currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
match = true;
break;
}
}
if(!match) {
// If the ID doesn't match then insert a new row
var newRow = sheetA.getRange(`A${rows.length+1}:D${rows.length+1}`);
newRow.setValues(currentRowB.getValues());
currentRowB.deleteCells(SpreadsheetApp.Dimension.COLUMNS);
}
}
sheetB.getRange("Z1").setValue('');
}
Note that every time the script runs it'll check if there's another one processing the rows by using Z1.
References
onEdit
Event Object
Related
I've got limited knowledge of google script and I'm trying to get better every day. I'm trying to conditionally set the value of 2 cells based on the value in cells contained in other rows. I've got a sample sheet (here) with appointments on it. You'll also see the output desired on the output sheet.
When two or more appointments are taken by the same person based on his email address I want to write Yes in column Duplicate for every duplicate appointments but the most recent (based on Column E, that is the date when the appointment was created) and that are greater than the current date (if the appointment is already in the past no need to do anything). I also want to set the value of the column L to "Not Coming" which is a cell containing a data validation that I already automated on my main spreadsheet.
Here is the script that I already designed based on other questions answered here on stackoverflow. I'm not really familiar with indexes and how to proceed with them. The script runs without errors but nothing happens.
var currentDate = new Date()
// Master
var sheetMaster = ss.getSheets()[0];
var allValues=sheetMaster.getRange(2,1,sheetMaster.getLastRow()-1,sheetMaster.getLastColumn()).getValues();
var emailValues=sheetMaster.getRange(2,3,sheetMaster.getLastRow()-1,3).getValues();
var dateCreatedAtValues=sheetMaster.getRange(2,5,sheetMaster.getLastRow()-1,5).getValues();
var duplicateColumn=sheetMaster.getRange(2,11,sheetMaster.getLastRow()-1,11);
var eM=[];//emails
var dA=[];//dates
var eR=[];//entire rows
var dC=[];//duplicateColumn Yes or empty
function analyzeDuplicateEntries() {
for(var i=0;i<emailValues.length;i++) {
var idx=eM.indexOf(emailValues[i][0]);
if(idx==-1) {
eM.push(emailValues[i][0]);
dA.push(dateCreatedAtValues[i][0]);
eR.push(allValues[i]);
}
else if(new Date(dateCreatedAtValues[i][0]).valueOf() > new Date(dA[idx]).valueOf() && new Date(dateCreatedAtValues[i][0]).valueOf()> currentDate) {
duplicateColumn[i][0].setValue("Yes");
}
}
} ```
You are retrieving the wrong column and set the values to a range cell incorrectly
var mailValues=sheetMaster.getRange(2,3,sheetMaster.getLastRow()-1,3).getValues(); will return columns 3 to 5 (see documentation, while your emails are in column B, that is column 2.
Pay attention that the first parameter in getRange(row, column, numRows, numColumns) is the number of the columns to retrieve, rather than the last column
Mind that to use setValue on a range that contains more than one cell, you need to retrieve first the respective cell with getCell()
Take thereby into consideration that the cell indexes start with 1 (opposed to array indexes that start with 0`).
A simple (not optimal) way to rewrite your code would be:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var currentDate = new Date()
// Master
var sheetMaster = ss.getSheets()[0];
var allValues=sheetMaster.getRange(2,1,sheetMaster.getLastRow()-1,sheetMaster.getLastColumn()).getValues();
var emailValues=sheetMaster.getRange(2,2,sheetMaster.getLastRow()-1,1).getValues();
var dateCreatedAtValues=sheetMaster.getRange(2,5,sheetMaster.getLastRow()-1,1).getValues();
var duplicateColumn=sheetMaster.getRange(2,11,sheetMaster.getLastRow()-1,1);
var eM=[];//emails
var dA=[];//dates
var eR=[];//entire rows
var dC=[];//duplicateColumn Yes or empty
function analyzeDuplicateEntries() {
for(var i=0;i<emailValues.length;i++) {
var idx=eM.indexOf(emailValues[i][0]);
if(idx==-1) {
eM.push(emailValues[i][0]);
dA.push(dateCreatedAtValues[i][0]);
eR.push(allValues[i]);
}
else if(new Date(dateCreatedAtValues[i][0]).valueOf() > new Date(dA[idx]).valueOf() && new Date(dateCreatedAtValues[i][0]).valueOf()> currentDate) {
duplicateColumn.getCell(i+1, 1).setValue("Yes");
}
}
}
I have searched high and low but I have been unable to find an answer (I am sure I am not explaining it right)
I have a Google Sheet that have multiple sheets (tabs) labeled TabA, TabB and TabC.
On this Google Sheet, I submit a slash command on Slack, which then auto-fills a row on one of the tabs using apps script.
What I am trying to do is simply insert a word called TabA into a specific cell each time a new row has been detected. And insert a word called TabB when a new row has been made on TabB sheet etc.
I am sure I just am typing my questions wrong which is why I am unable to find an answer.
I am not actually sure which part of the code posts to the sheet, I think it is this?
if(sheetName) {
sheetName = sheetName.charAt(0).toUpperCase() + sheetName.slice(1)
} else {
sheetName = "Current"
}
// Find sheet
var sheetFlag = false;
for (var r = 1; r < settings.length; r++) {
if (settings[r][1] == channelID) {
var sheetID = settings[r][2];
var targetChannelID = settings[r][4];
var title = settings[r][0];
sheetFlag = true;
break;
}
}
if (sheetFlag) {
var sheet = SpreadsheetApp.openById(sheetID).getSheetByName(sheetName);
if(!sheet) {
sheet = SpreadsheetApp.openById(sheetID).insertSheet(sheetName);
}
var lastRow = sheet.getLastRow();
var slackDetails = ["", "", text1, "","","","","",realName, new Date(),title,text2];
// paste the slack details to the sheet
sheet.getRange(lastRow + 1,1,1,slackDetails.length).setValues([slackDetails]);```
Thank you in advance
If I understood you correctly, you want to:
Keep track of new rows that are added to each sheet in your spreadsheet (TabA, TabB, TabC).
Write the name of the sheet in successive rows of column D of each sheet every time news rows are detected.
As you were told in the comments, Apps Script has no triggers to track changes made to the spreadsheet by a script. For example, onEdit trigger "runs automatically when a user changes the value of any cell in a spreadsheet".
Workaround (time-based trigger and script properties):
A possible workaround to this limitation is using a time-based trigger that will fire a function periodically. You can create this trigger manually, or programmatically, by running this function once:
function createTrigger() {
ScriptApp.newTrigger("trackRows")
.timeBased()
.everyMinutes(1)
.create();
}
This will fire the function trackRows every minute. This function's purpose is to track changes to each sheet rows since last time it was fired (in this example, 1 minute ago) and write the sheet name to a certain cell if the sheet has more rows with content than during last execution.
To accomplish this, you can use the Properties Service, which lets you store key-value pairs and use them in later executions.
The function trackRows could be something along the following lines:
function trackRows() {
var props = PropertiesService.getScriptProperties();
var ss = SpreadsheetApp.openById("your-spreadsheet-id"); // Please change accordingly
var sheets = ss.getSheets();
sheets.forEach(function(sheet) {
var sheetName = sheet.getName();
var currentRows = sheet.getLastRow();
var oldRows = props.getProperty(sheetName);
if (currentRows > oldRows) {
var firstRow = 2;
var column = 4;
var numRows = sheet.getLastRow() - firstRow + 1;
var rowIndex = sheet.getRange(firstRow, column, numRows).getValues().filter(function(value) {
return value[0] !== "";
}).length;
var cell = sheet.getRange(rowIndex + firstRow, column);
cell.setValue(sheetName);
}
props.setProperty(sheetName, currentRows);
});
}
This function does the following:
Retrieve the script properties that were stored in previous executions.
Get all the sheets in the spreadsheet.
Check the last row with content in each sheet (via Sheet.getLastRow()), and compare the value with the one previously stored in script properties.
If the current last row is higher than the one stored in properties, write the sheet name in the first empty row of column D of the corresponding (starting at D2).
Store the current last row in script properties.
Notes:
The script is adding the sheet name to the first empty row of column D once, if it detects that new rows were added. It's not taking into account how many rows were added since last execution, it only considers if rows were added. This could easily be changed though, if that's what you wanted.
If you want to start from fresh, it would be useful to delete all previously stored properties. To do that, you could run this function once:
function deleteProps() {
var props = PropertiesService.getScriptProperties();
props.deleteAllProperties();
}
Reference:
Class ClockTriggerBuilder
Class PropertiesService
Sheet.getLastRow()
I used =QUERY(IMPORTRANGE..) to import data from Sheet 1 to Sheet 2 for Column A, B & C. I have to take note in Column D of Sheet 2 for each entry imported. However, for any new one added, the note (for the previous ones) in Column D stays in the same cells. For example, the formula is in A2, so the new data will be added to A2,B2 & C2. The note is in D2. When a new one is imported, the previous one moved to A3, B3 & C3. However, the note is still in D2.
Is there any way to make those notes to move to the next row automatically when a new entry is added?
Here are the files the data has to be imported to and from: https://drive.google.com/drive/folders/1wbOfW9PbSfJbTBv_CwXOTiyyN_LBTiFq?usp=sharing
If my understanding is correct, you want to accomplish the following:
Import data from one spreadsheet to another using IMPORTRANGE.
Add notes manually to a column in your destination spreadsheet.
When a new row is imported to the destination spreadsheet and make previously imported data, the notes should move too.
To achieve that, you would need to keep track of which note belongs to which row of imported data. Both sets of data should be somehow attached. Considering that you have a timestamp in column A, and that this timestamp is probably unique for each row, this timestamp could be used to attach both (if that's not possible, I'd propose adding another column that will be used to identify each row without ambiguity, via some kind of id).
At this point, I would consider using Google Apps Script to accomplish your needs. With this tool, you could develop the functionality that =QUERY(IMPORTRANGE(...)) is providing right now, and you could use other Apps Script tools to reach the desired outcome. Two tools could be specially necessary to accomplish this:
onEdit triggers, to keep track of when the different spreadsheets are edited and make the appropriate changes if that's the case (basically, copying data from one spreadsheet to another).
Properties Service, to store the information about which note is attached to which row of data.
You could do something on the following lines:
Install two edit triggers, (1) one that will fire a function when the source spreadsheet is edited, and (2) another one that will fire when the destination spreadsheet is edited (a simple trigger cannot be used because you have to reference files to which your spreadsheet might not be bound). You can do this manually or programmatically.
Create a function that, for each note that is added to the destination sheet (in this code sample, that's in column D, please change according to your preferences), stores a key-value pair where the key is the value in column A (which should uniquely identify a row of data) and value is the note. This will be used later for the script to know where each note belongs to:
function storeNotes(e) {
var scriptProperties = PropertiesService.getScriptProperties();
var cell = e.range;
var sheet = cell.getSheet();
var rowIndex = cell.getRow();
var column = cell.getColumn();
var noteColumn = 4; // The column where notes are written, change accordingly
// Check whether correct sheet, column and row is edited:
if (column == noteColumn && rowIndex > 1 && sheet.getName() == "Destination") {
var row = sheet.getRange(rowIndex, 1, 1, sheet.getLastColumn()).getValues()[0];
scriptProperties.setProperty(row[0], row[noteColumn - 1]); // Store property to script properties
}
}
Create a function that, every time the source spreadsheet is edited, will delete all content in the destination spreadsheet and copy the data from the source. Then, it will look at the script properties that were store and, using this information, it will write the notes to the appropriate rows (because I see you only want to copy/paste some of the columns, in this sample some of the columns - the ones whose index is in columnsToDelete - are not copied/pasted, you can change this easily to your preferences):
function copyData(e) {
var range = e.range;
var origin = range.getSheet();
var row = range.getRow();
if (origin.getName() == "Origin" && row > 1) { // Check if edited sheet is called "Origin" and edited row is not a header.
var dest = SpreadsheetApp.openById("your-destination-spreadsheet-id").getSheetByName("Destination");
var firstRow = 2;
var firstCol = 1;
var numRows = origin.getLastRow() - 1;
var numCols = origin.getLastColumn();
var values = origin.getRange(firstRow, firstCol, numRows, numCols).getValues();
// Removing some of the columns to get copied/pasted (in this case B and D):
var columnsToDelete = [1, 3];
values = values.map(function(row) {
for (var i = row.length; i > 0; i--) {
for (var j = 0; j < columnsToDelete.length; j++) {
if (i == columnsToDelete[j]) {
row.splice(i, 1);
}
}
}
return row;
})
// Copying content from source to destination:
var firstRowDest = 2;
var firstColDest = 1;
var numRowsDest = values.length;
var numColsDest = values[0].length;
var noteColumn = 4;
var currentValues = dest.getDataRange().getValues();
if (currentValues.length > 1) dest.deleteRows(2, dest.getLastRow() - 1);
var importedRange = dest.getRange(firstRowDest, firstColDest, numRowsDest, numColsDest);
importedRange.setValues(values);
// Writing notes stored in Properties in the appropriate rows:
var properties = PropertiesService.getScriptProperties().getProperties();
for (var i = 0; i < values.length; i++) {
for (var key in properties) {
if (key == values[i][0]) {
dest.getRange(i + 2, noteColumn).setValue(properties[key])
}
}
}
}
}
Notes:
All these functions should be in the same script if you want all both functions to use Properties.
In this sample, the sheet with source data is called Origin and the sheet where it is copied is called Destination (from what I understood, they are in different spreadsheets).
In this simplified example, columns A, B, E from source sheet get copied to columns A, B, C of the destination sheet, and notes are added to column D. Please change this to fit your case by modifying the corresponding indexes.
I hope this is of any help.
Thank you everyone for helping me, especially Lamblichus & user11982798. I recently noticed that importrange will import data to the destination in the same order as that of the source file. Before I sorted the data based on the timestamp in descending order so the new entry was always on the first row. If I changed it to ascending order, the new one is added to the last row, so the note/comment order will not be affected.
Is it possible to update the note/comment in the destination file back to the source one?
If the note is string please try to put in D2 like this:
=ARRAYFORMULA(if(row(A2:A) = max(arrayformula(if(ISBLANK(A2:A),0,row(A2:A)))),"Your Note", ""))
This will automatically place your note to last row of data
I have attached the following link to my Google spreadsheet.
Spreadsheet
In the sheet called "Qualifications" is a list of employees and personal data. When an employee leaves, the user will click the "Employee Left" button which opens up Column B. The intention is that the user will then add next to the employee's name, the date the employee left and once the user presses enter the respective row will be cut and pasted into the sheet titled "Qualifications - Employees Left" and Column B will be hidden again. This is my way of trying to archive the data and still have access to it just in case the employee returns.
I have started an apps script on row 194 of the Script Editor. I was initially going to just hide the row but I don't want all of the little arrows when a row is hidden in Google Sheets. I am now struggling with the code and would appreciate some help.
If I understand you correctly, you want to:
(1) Unhide column B when the button Employee Left is clicked (in Qualifications).
(2) If the user writes a date in the column Date Left (in Qualifications), all the data in the corresponding row getting cut & paste to the first empty row in Qualifications - Employees Left, and column B gets hidden again.
I modified your script so that it accomplishes these tasks.
First, it looks like the function EmployeeLeft you wrote already does what it's supposed to do, but I reworked it a bit. I'm not sure why you want to activate and then unhide column C, but anyway, whatever suits you. This is the one I wrote:
function EmployeeLeft() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var colIndex = 2;
sheet.showColumns(colIndex);
sheet.getRange("B5").activate();
}
Then comes the main part. In order to accomplish point (2), I wrote a function inside an onEdit trigger. I am aware you already have an onEdit function, but I think there shouldn't be any problem integrating this code inside it.
Basically, this function checks whether the edited cell is from sheet Qualifications, from column B, not from a header row, and that the edited value is a valid Date. If all these conditions are met, the edited row is removed from Qualifications and its values are copied to the first empty row in Qualifications - Employees Left. Finally, column B becomes hidden again, until Employee Left is clicked again.
Here is the function:
function onEdit(e) {
var ss = e.source;
var sheet = ss.getActiveSheet();
var sheetName = "Qualifications"
var range = e.range;
var editedColumn = range.getColumn();
var editedRow = range.getRow();
var column = 2;
var date = range.getValue();
// Object.prototype.toString.call(date) === '[object Date]' --> checks if value is date
// editedColumn == column && editedRow > 4 --> checks if edited cell is from 'Date Left'
// sheet.getName() == sheetName --> checks if edited sheet is 'Qualifications'
if(Object.prototype.toString.call(date) === '[object Date]' && editedColumn == column && editedRow > 4 && sheet.getName() == sheetName) {
var numCols = sheet.getLastColumn();
var row = sheet.getRange(editedRow, 1, 1, numCols).getValues();
var destinationSheet = ss.getSheetByName("Qualifications - Employees Left");
// Get first empty row:
var emptyRow = destinationSheet.getLastRow() + 1;
// Copy values from 'Qualifications'
destinationSheet.getRange(emptyRow, 1, 1, numCols).setValues(row);
sheet.deleteRow(editedRow);
sheet.hideColumns(column);
}
}
Take into account that there is some data in some rows far below the headers in "Qualifications - Employees Left". Make sure that you remove all these data so that values get copied in the appropriate rows.
Update
Here I share a copy of the spreadsheet with the correct script attached. I'd advice you to copy the full script and paste it in the file you're working on, removing all previous content:
https://docs.google.com/spreadsheets/d/1XCrcSaDwwmKTHLIxL9vbx0_t6NJew983d9YDol-Y1dw/edit?usp=sharing
The function onEdit(e) is added on top, including both, the one I wrote and the one you had already written.
Regarding the function Employee Left, I commented out the one you wrote and added mine below. If you prefer yours, just remove mine and uncomment yours.
I hope this is of any help, and please tell me if that works for you.
This code will delete complete the row with active cell, and add it to the new sheet at the end. Remember to replace the values containing <> with actual ones.
function remove_and_reinsert_row() {
var sheet = SpreadsheetApp.getActiveSheet();
var active_range = sheet.getActiveRange();
var last_column = sheet.getLastColumn();
var tbd_row_data = sheet.getRange(active_range.getRowIndex(), 1, 1,last_column).getValues();
sheet.deleteRow(active_range.getRowIndex());
var new_sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("existing sheet name");
var last_active_row = new_sheet.getLastRow();
new_sheet.getRange(last_active_row+1, 1, 1,tbd_row_data[0].length).setValues(tbd_row_data);
}
This will use row with active range, i.e. and cell which is currently active and delete the row , inserting it into new sheet. You can use trigger on the column and see whenever someone changes value in the column, and trigger the function using app script triggers.
For hiding a column, you can use following function:
sheet.hideCoumns(colIndex);
Hope this helps,
I have a mastersheet named "ENTRATE MAIN", I want to copy range "A2:J50" to the last column of another sheet whose name is found in Cell Z1 in the Mastersheet. But the code needs to check if the data is already copied first.
I'm actually new to Google App Script, so I've actually tried using some formulas but they dont do the job since the data in the master sheet is dynamic.
I have looked at the code in this URL but it doesn't exactly what I want. Copy data from one sheet to the last row of another sheet
I expect to check if the master sheet data is already there in the other sheet. I also need it to copy to the last row of the sheet name in cell Z1 of mastersheet
Maybe this is what you are looking for. Keep in mind that it's not possible to check for the Master data in the second sheet without using the name in Z1, unless you manually input the name of the second Sheet in the code first.
function main(){
//Master Sheet
var sprsheet = SpreadsheetApp.getActiveSpreadsheet();
var master_sheet = sprsheet.getSheetByName("ENTRATE MAIN");
var master_range = master_sheet.getRange("AJ2:J50");
//Second Sheet
var sheetName = master_sheet.getRange("Z1").getValue();
var second_sheet = sprsheet.getSheetByName(sheetName);
var lastrow = second_sheet.getLastRow();
var master_data = master_range.getValues();
if (lastrow > 50){ //This is in case your second sheet has less than 50 rows before copying the data
//We have to check the previous 49 rows in case the data is already there
var second_range = second_sheet.getRange("AJ"+(lastrow-49)+":J"+(lastrow));
var second_data = second_range.getValues();
if (!isCopied(master_data, second_data)){
//Data is not there so we copy it in the next 49 rows
//If you want to overwrite the last row, just remove the +1
second_range = second_sheet.getRange("AJ"+(lastrow+1)+":J"+(lastrow+49));
second_range.setValues(master_data);
}
} else {
//The second sheet has less than 50 rows so the data is obviously not there
var second_range = second_sheet.getRange("AJ"+(lastrow+1)+":J"+(lastrow+49));
second_range.setValues(master_data);
}
}
function isCopied(master_data, second_data){
for (i in master_data){
for (j in master_data[i]){
if (master_data[i][j] != second_data[i][j]){
return false;
}
}
}
return true;
}