In the image below, Table 1 is an editable table where a user can change the values. Table 2 is a master table that I want to update with the changed values from Table 1. The unique identifier for each table is the Full Name (Column A). In this example, I'd like to:
Get the data from Table 1 associated with the Full Name entered into B1 (Washington, George).
Update the right record in Table 2 (row 13) with the values from Table 1.
Table 1 and Table 2
I know that I can use getvalues() and setvalues() to get the data from Table 1 and write it into Table 2. I'm having trouble figuring out how to get the right range (row 6 in Table 1 for the getvalues() function and row 13 in Table 2 for the setvalues() function) based on the value in B1 (Washington, George).
If I were using Excel VBA, I'd do a search in Table 1 and Table 2 for the value in B1 and then select the entire row. I've read articles about how to get a range based on A1 notation, user selection, and column/row identification, but I can't find anything related to getting a range relative to the location of a specific value in the data set.
Use this to read the data in the sheet:
const sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
const data = sheet.getDataRange().getValues();
Follow with this to find the row index of searchValue:
const keys = data.map(row => row[0]);
const rowIndex = keys.indexOf(searchValue);
To write a values array in the row, use this:
sheet
.getRange(rowIndex, 1)
.offset(0, 0, 1, values.length)
.setValues(values);
Some of the best resources for learning Google Apps Script include the Beginner's Guide, the New Apps Script Editor guide, the Fundamentals of Apps Script with Google Sheets codelab, the Extending Google Sheets page, javascript.info, Mozilla Developer Network and Apps Script at Stack Overflow.
Related
I am using google sheets to track my investments. Now I want to record the total investment value from L11 in "Portfolio" sheet every day at 4 PM to "Dashboard" sheet. Now I tried to use the code available online but it is showing an error in the last line.
function scorekeeper(){
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Portfolio");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Dashboard");
var score = sheet1.getRange("L11").getValue();
var row = sheet2.getRange("A1").getValue();
sheet2.getRange(row,2).setValue(score );
}
Error
Exception: Cannot convert '' to int.
scorekeeper.
So how to do this properly and then add trigger to this. I have to use that data to plot a graph for visual presentation.
I am quite sure that cell A1 is empty, and it is supposed to contain the row number of the destination sheet, where you want the value to be stored.
Maybe adding
SpreadsheetApp.flush()
before
var score = sheet1.getRange("L11").getValue();
would help, if you A1 contains a formula that calculates the row number. Otherwise, check its content or set the row variable value to a number.
I have two googlesheets, In one google sheet (let's call it A) I am uploading the data using R cron and in another sheet (let's call it B) I'm importing the data from A using importrange formula.
In B, I am importing the data in sheet1 but I want to automatically copy the data from Sheet1 in Sheet2 whenever the Sheet1 gets updated. Also, I want to ensure that the new updated data gets append in Sheet2 without changing the sequence of previous records.
For Example,
If in B, Sheet1 has 5 records as mentioned below then copy it in new tab as Sheet2 and if in Sheet1 new data gets upload (suppose now there are 10 records in sheet1) then new uploaded five records should get appended in Sheet2 without changing the sequence and anything updated against records 1-5.
ID Name Date
1 ABC 2020-01-01
2 ART 2020-01-02
3 XUZ 2020-01-03
4 AFI 2020-01-03
5 SSR 2020-01-02
Sheet - https://docs.google.com/spreadsheets/d/1pY5dvlrEf39ul7sqmzyBI1Hwoplh9_7eNGveeVfUQZA/edit?usp=sharing
I've added a tab, Sheet2-GK, to your sheet. This demonstrates using the ID value as an index in Sheet2, to allow manual data to be entered alongside dynamic data, which is updated from Sheet1 by formula.
The key formula, in Sheet2!B2, would be:
=ARRAYFORMULA(VLOOKUP(A2:A6,Sheet1!A$1:C,{2,3},0))
Without more sample data, I can't test the results, but let me know if this works for you, as you add fresh data to Sheet1.
I have a dashboard that is reporting live data based on a growing customer database, and I am currently tracking the daily process by copying and pasting the data in the column into the next on a daily basis.
I'd like to create a script that automatically copies the values from an array (B:B) for example, into another sheet OR into the next available column to the right.
You may refer to the image below for further clarity.
Sample
I saw may threads on this but they were all about copying into a different row, as opposed to a different column.
Many thanks in advance!
The getLastRow() method is used to return the position of the last row that has content.
The getLastColumn() method is used to return the position of the last column that has content.
Therefore, in order to be able to copy the data into the next available column, I suggest you try this:
function copyColumn() {
var ss = SpreadsheetApp.openById("ID_OF_THE_SPREADSHEET");
var sheetFrom = ss.getSheetByName("SHEET_FROM");
var sheetTo = ss.getSheetByName("SHEET_TO");
var values = sheetFrom.getRange(NO_OF_THE_ROW_WHERE_DATA_STARTS, 3, sheetFrom.getLastRow(), 1).getValues();
sheetTo.getRange(NO_OF_THE_ROW_WHERE_DATA_STARTS,sheetTo.getLastColumn()+1,values.length,1).setValues(values);
}
The above script localizes all the data that needs to be copied by using the getRange() method and is copied by using getValues().
NO_OF_THE_ROW_WHERE_DATA_STARTS is the value representing the number of the row where your data starts (in your case the row of No of LP - Secured);
3 is the value representing the C column (where the data you want to be copied is located);
sheetFrom.getLastRow() is the value representing the end of the data you want to be copied;
1 is the value representing the number of columns that need to be copied.
Afterwards, the getRange() method is used again in order to be able to identify where the data needs to be pasted and setValues() in order to actually paste it.
Note: The above script works for different spreadsheets and/or different sheets OR for sheets in the same spreadsheet. If you want to use it for the latter case, you just have to put the name of your sheet instead of SHEET_FROM and SHEET_TO.
Moreover, I suggest you check the following links since they might be of help:
Sheet Class Apps Script - getRange();
Range Class Apps Script - getValues();
Range Class Apps Script - setValues();
Sheet Class Apps Script - getLastColumn();
Sheet Class Apps Script - getLastRow();
what i'm trying to do is to update data in a google sheet and then write that data back to the sheet.
1. I read the data from the spreadsheet
2. Go over the data if needed i add a row and add columns, i.e. i change the existing data.
3. now i need to write the data back in the spreadhsheet
the only thing that i can think of is that the range is bigger than the old range of column and rows and this might be causing the problem
//Reading the data initially:
var workingSheet = SpreadsheetApp.getActive().getSheetByName(storeSheetName);
var existingData = workingSheet.getDataRange().getValues(); //row 0 is column names
//do some manipulations on the data (add rows and columns)
// Writing the values :
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(storeSheetName).getRange(1,1,existingData.length,storeColumns.length).setValue(existingData);
when i try running the script in debug mode , it keeps getting stuck on the .setValues() row and will not proceed
consider this situation.
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("2:2");
var values = range.getValues();
values[0][0] = "updated value"; //updating retrieved data
sheet.insertRowAfter(1); //here the problem appears
range.setValues(values); //trying to save updated row data - FAIL!
Updated row values will be written in a row number 2 (as per range selector "2:2") not in new position "3:3".
Result: It will overwrite data at row 2 instead of updating previously selected/loaded row, which is now at position "3:3" and not anymore at "2:2".
Im looking for a way how to keep "address" of a range even when the range was shifted because of added/removed rows/cells somewhere else in the sheet.
In this dummy example I can track range changes. But in parallel processing/updating sheet i can't simply track all changes from many different places.
So far I came up with a solution add new rows only at the end of SS (that doesn't change range of any rows above, but I would like to have ability add new rows on top of sheet without influencing already selected ranges.
Deleting rows is also dangerous situation - it changes position of ranges also.
LockService can't really solve the situation, because I have plenty scripts working on the same sheet (not using centralized library because of speed performance in addon).
Metadata for cell or row seems too complicated to handle for such an easy task.
From my point of view Object Range should keep its position even when its moved/shifted somewhere else. Otherwise I can't see reason to have Range as an Object - if it keeps only fixed information about from where it was picked.
Any advices are welcomed. Thank you in advance..
EDIT:
Just to add a context. I'm using Google sheets as a database for orders (10 thousands so far) - each row means one order (customer) and not all orders are in one sheet - different products have different sheets (+- 10 products/sheets)
There is an suggestion using named ranges to solve this issue - So what will happen if a spreadsheet will have ten of thousands named ranges - can that work without serious performance issues? Im thinking about to creating named range for each order row, so I can easily pick up right row by orderId and not to be afraid of moving a row when new order arrive during processing another one
You want to achieve the following flow.
Retrieve the value from "2:2" (row 2).
Modify the retrieved value.
Insert a row just below of the row 1.
By this, the initial row 2 is moved to the row 3.
Put the retrieved value to the row 3 which is the initial row 2.
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 answers.
Issue and solution:
In your script, range of var range = sheet.getRange("2:2"); is the constant. By this, even when the row is inserted, this value is not changed. This is the reason of your issue.
I think that the idea using the named range will be resolved for your situation. But your comment says as follows.
I just found, that namedRange is not capable actualize its own address, if something had changed in the sheet after initialize of a range.
When the row 2 is installed as the named range, when a row is inserted to just below of the row 1, the range of the named range is also changed. But from your comment, I thought that the named range might have not been reloaded.
In order to confirm this, I would like to propose a sample script.
Sample script:
Before you run the script, please install a named range to row 2 as the name of sampleNamedRange. Then, run this script.
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Added
var sheet = ss.getActiveSheet(); // Modified
// Retrieve the range from the namedRange.
// namedRange of "sampleNamedRange" is installed for the range of "2:2" of the active sheet.
var range = ss.getRangeByName("sampleNamedRange"); // Modified
var values = range.getValues();
values[0][0] = "updated value"; //updating retrieved data
sheet.insertRowAfter(1);
// Retrieve the range from the updated namedRange.
var range = ss.getRangeByName("sampleNamedRange"); // Added
range.setValues(values);
Result:
Note:
The point is to retrieve the range from the updated named range. By this, the updated range can be used. So in above script, the updated value is put to the row 3.
References:
getRangeByName()
Class NamedRange
If I misunderstood your question and this was not the result you want, I apologize