Using a Google App Script I'm looking to find any ID's from Sheet2 which exist in Sheet1 and append the comment field within Sheet1 with what is listed in the Comment field in Sheet2.
Sheet1: Holds all data based on ID
Sheet2: Holds comments relating to some ID's in Sheet1
Sheet1 Example
ID Type In Stock Comment
1 Apple Yes
2 Banana No
3 Orange Yes
Sheet2 Example
ID Comment
1 Text
2 Text
Code
This is code I've been using for something else which loops through my source data to identify a variable called "Yes", obviously this won't work for this case as the ID is the variable we need to find which is dynamic.
I'm just a bit lost on how to modify this code so that it will loop through Sheet2, get all the IDs, check those IDs against Sheet1. If those IDs exist in Sheet1 update the comment of Sheet1 with the comment already listed in Sheet2
function setComment(){
var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var lastRow = outputSheet.getLastRow();
var lastCol = outputSheet.getLastColumn();
var targetValues = [];
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var lastSourceRow = sourceSheet.getLastRow();
var lastSourceCol = sourceSheet.getLastColumn();
var sourceRange = sourceSheet.getRange(1, 1, lastSourceRow, lastSourceCol);
var sourceData = sourceRange.getValues();
{
//Loop through every retrieved row from the Source
for (row in sourceData) {
//IF Column I in this row has 'Yes', then work on it.
if (sourceData[row][1] === 'Yes') {
//Save it ta a temporary variable
var tempvalue = [sourceData[row][0], sourceData[row][7]];
//then push that into the variables which holds all the new values to be returned
targetValues.push(tempvalue);
}
}
//Save the new range to the appropriate sheet starting at the last empty row
outputSheet.getRange(lastRow + 1, 1 , targetValues.length, 2).setValues(targetValues);
}
}
Yes you need to loop through one group of IDs. In that loop you need to nest a loop that goes through the other group of IDs.
Code
function setComments() {
var ss = SpreadsheetApp.getActive(),
compare1 = "", compare2 = "",
outputSheet = ss.getSheetByName("Sheet1"),
sourceSheet = ss.getSheetByName("Sheet2"),
range1 = outputSheet.getDataRange(),
range2 = sourceSheet.getDataRange(),
lastCol1 = range1.getNumColumns(),
lastCol2 = range2.getNumColumns(),
values1 = range1.getValues(),
values2 = range2.getValues(),
// get the range of the titles
titleSection1 = outputSheet.getRange(1,1,1, lastCol1),
titleSection2 = sourceSheet.getRange(1,1,1, lastCol2),
// get the values from the titles
titles1 = titleSection1.getValues(),
titles2 = titleSection2.getValues(),
// get the column # for "ID" and "comment"
idCol1 = titles1[0].indexOf("ID"),
idCol2 = titles2[0].indexOf("ID"),
commentsCol1 = titles1[0].indexOf("comment"),
commentsCol2 = titles2[0].indexOf("comment");
// get the IDs from range1
for (i = 1; i < values1.length; i++) {
compare1 = values1[i][idCol1];
// get the IDs from range2
for (j = 1; j< values2.length; j++){
compare2 = values2[j][idCol2];
// if same ID, change the values array
if (compare1 == compare2) {
values1[i][commentsCol1] = values2[j][commentsCol2];
}
}
}
// set values based on the values array
range1.setValues(values1);
}
Related
The code below is from here and was originally written by user #Cooper. All it does is that it copies the values of the columns specified in the array colA = [1,3,2,4] from SHEET 1 and add them to SHEET 2. I want to re-write the 2 last lines of the code, so that the values coming from SHEET 1 are added to the last available rows in SHEET 2. By "2 last lines", I mean these last lines of the code:
drng = des.getRange(1,1,drngA.length,drngA[0].length);//destination array controls size of destination range.drng.setValues(drngA);
Any idea how to get this done?
Thank you so much in advance for your help!
function Copy_data()
{
var src = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SHEET 1");
var des = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SHEET 2");
var srng = src.getDataRange();
var srngA = srng.getValues();
var drngA = [];
var colA = [1,3,2,4];//indirect data column selection
for (var i = 0; i < srngA.length;i++ )
{
var k = 0;
drngA[i]=[];
for(var j=0;j<srngA[i].length;j++)
{
drngA[i][k++] = srngA[i][colA[j]-1];
}
drng = des.getRange(1,1,drngA.length,drngA[0].length);//destination array controls size of destination range.
drng.setValues(drngA);
}
}
You can get the last row of the destination Sheet and after, add it to your getRange() function. The method proposed by #soMario will not work because it makes requests inside the loop while you update the Sheet, and this causes it to get different values every time you call des.getLastRow().
The simplest solution is to take the getLastRow() request outside of the loop and then include it in getRange. Note that one is added to it so that it does not overwrite the last row with the setValue() request.
Code.gs
function Copy_data() {
...
var lastRow = des.getLastRow() + 1
for (var i = 0; i < srngA.length;i++ ){
...
drng = des.getRange(lastRow,1,drngA.length,drngA[0].length)
...
}
Documentation
getRange(row, column, numRows, numColumns)
getLastRow()
I'm trying to write a script which has multiple parts. The current part (function copyOver) supposed to open a spreadsheet (by ID), extract specific data from it and insert it into a Master spreadsheet.
The part I'm stuck with is that the spreadsheet changes daily. Some days there are cells containing data of "Sea Water", other days there aren't any. Ideally, I was trying to write a script which loops through the sheet looking for the specific tab names in cells (for example: Sea water, chlorine content...) and extract the data from the row below, up until the second tab and so on. I would only need very specific data, like data from "C6", "E6", "F10", but these cells are always changing so I have to look for them by using the tab names in cells above them. There would be multiple arrays for each tab and the data coming with it.
Would that be possible to extract data this way and put them into an array containing the tab value as the header or title and the data connected to that specific tab.
var sourceID = "source sheet ID";
var main = SpreadsheetApp.openById("master sheet ID"); // MASTER
var source = SpreadsheetApp.openById(sourceID); //the workbook you're copying from
var mainsheet = main.getSheetByName("Lab Data"); // the sheet you want to copy the stuff into
var sourcesheet = source.getSheetByName("ANALYSIS REPORT"); // the sheet you're copying from
var dataRange = sourcesheet.getDataRange().getValues(); // gets sheet as data range
// finds SEA WATER tab in cell and gets the range below until the end of the document
// this is the range I need to find the rest of the tabs and the data under them.
var cont = "SEA WATER";
var i = [];
for (var y = 0; y < dataValues.length; y++){
if(dataValues[y] == cont){
i.push(y);
} // end if
} // end for
Logger.log(i);
var Row = Number(i)+Number(dataRange.getRow()); // gets the row number of SEA WATER tab
Logger.log("row number: " + Row);
var swLast = sourcesheet.getLastRow();
var swRange = sourcesheet.getRange(Row,2,swLast,11);
var swValues = swRange.getValues(); // range of needed information
Logger.log("sw: " + swValues);
var con2 = "SW outlet SW from Coarse filtration"; // looking for the secondary tab, within the
range
I got from the first loop
var res2 = [];
for(var i2 = 0; i2 < swValues.length; i2++) {
if(swValues[i2][4] === con2) res2.push(data[i2])
var row2 = Number(i2)+Number(swRange.getRow());
Logger.log("row2 " + row2);
} // for end
var look1 = "SW outlet SW from Coarse filtration ";
for(var i1 = 0; i1<dataRange.length;i1++){
if(dataRange[i1][1] == look1){
return i1+1;
}
}
Logger.log((i1+1));
} // end of function
EDIT: Here's a link to a sheet. Required data starts from row 237, until row 268 - but this can change every day. (Deleted the information for privacy reasons.)
Basically, I need all the cells with "x" in them, preferably together with the title cells above them, so I'll know what data it is.
The following code loops through your headers in column B and finds the row in which your header of interest is located
Subsequently, it copies the data starting from this row to the last data row into the sheet "Lab Data":
function myFunction() {
var sourceID = "source sheet ID";
var main = SpreadsheetApp.openById("sourceID"); // MASTER
var source = SpreadsheetApp.openById(sourceID); //the workbook you're copying from
var mainsheet = main.getSheetByName("Lab Data"); // the sheet you want to copy the stuff into
var sourcesheet = source.getSheetByName("ANALYSIS REPORT"); // the sheet you're copying from
var dataRange = sourcesheet.getDataRange()
var dataValues=dataRange.getValues(); // gets sheet as data range
for (var a = 0; a < dataValues.length; a++){
if(dataValues[a][1]=="SEA WATER"){
var Row=a+1;
break;
}
}
if(Row){
var swLast = sourcesheet.getLastRow();
var swRange = sourcesheet.getRange(Row,2,swLast,11);
swRange.copyTo(mainsheet.getRange(mainsheet.getLastRow()+1, 2));
}
} // end of function
I hope this helps to solve your issue.
I am quite new to Google Script, I'm learning on the job.
I have a range of data as a variable. It's only one column, column F in this case, but there are empty cells between values. I have a working script (got it from here earlier), which only loops through the cells with values in them. So lets say value1 is in F5, value2 is in F13, it's all random and always changing.
I'm trying to get the row number for these values, so that script should give back "5" for value1 and "13" for value2, ideally together with the value itself.
So far, that's what I have and I can not seem to progress further.
var sourceID = "sourceID";
var main = SpreadsheetApp.openById("mainID");
var mainsheet = main.getSheetByName("Lab Data");
var sourcesheet = source.getSheetByName("sheet name");
var dataRange = sourcesheet.getDataRange(); // range full sheet
var values = dataRange.getValues(); // values full sheet
var SWrowss = findCellForSW(); // getting start row from another function
var CQrowss = findCellForCQ(); // getting last row from another function
var noRows = CQrowss - SWrowss; // gets number of rows in range
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues(); // range we need, column F
// get rid of empty cells from range - copied script from stack overflow
var cResult = colss.reduce(function(ar, e) {
if (e[0]) ar.push(e[0])
return ar;
}, []);
Logger.log("cResult: " + cResult); // cResult contains all sub headers - no empty cells
// gets element's position in array
for(var b = 0; b < cResult.length; b++){
var position = b+1;
Logger.log("pos " + position);
} // end for
If you want to know the row number, I would propose you a different approach
Just loop through your values and retrieve the position of the ones that are not empty:
...
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rows = [];
var calues = [];
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
var row = SWrowss+b+1;
rows.push(row);
var value = colss[b][0];
values.push(value);
}
}
...
With the other solution you can build a single object that can do the conversion for you very quickly.
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rvObj={};
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
rvObj[colss[b][0]]=SWrowss+b+1;
}
}
With rvObj now you can get any row with var row = rvObj[value];
I'm new to JavaScript... I have 2 spreadsheets created. 1 that has input values, and the 2nd is a target sheet where I want to update information.
I am searching through the target sheet with values from the input sheet with a column labeled "OpportunityID". Once the associated row is found, I want to update the target row with the values from the input sheet.
I've been able to search the target sheet with OpportunityID value from the input sheet and pull the values of columns in that specific row, but I am having trouble changing the values on the target sheet to the corresponding values on the input sheet.
Here is the code I have tried so far that pulls the appropriate information, but I need help resetting the values of that row:
function updateOpportunity() {
// Get active spreadsheets and sheets
var inputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Search & Create New Records');
var OppsAndContracts = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Opportunities & Contracts');
var opportunityUpdateCopy = inputSheet.getRange('A8:Q8').getValues();
Logger.log(opportunityUpdateCopy);
//Search for Opportunities using OpportunityID
var last=OppsAndContracts.getLastRow();
var data=OppsAndContracts.getRange(1,1,last,17).getValues();// create an array of data from columns A through Q
var opportunityID = updateSheet.getRange("A8").getValue();
Logger.log(opportunityID);
for(nn=0;nn<data.length;++nn){
if (data[nn][0]==opportunityID){
var OppID = (((data[nn][0])));
var OppName = ((data[nn][1]));
var AccountID = ((data[nn][2]));
var AccountName = ((data[nn][3]));
var OppOwner = ((data[nn][4]));
var CloseDate = ((data[nn][5]));
var Amount = ((data[nn][6]));
var ProposalOwner = ((data[nn][7]));
var Stage = ((data[nn][8]));
var AeroServicesProducts = ((data[nn][9]));
var MechServicesProducts = ((data[nn][10]));
var ProjectStatus = ((data[nn][11]));
var PaymentIssues = ((data[nn][12]));
var UniquePaymentTerms = ((data[nn][13]));
var PaymentTerms = ((data[nn][14]));
var ProposalNumber = ((data[nn][15]));
var ContractNumber = ((data[nn][16]));} ;
OppsAndContracts.getRange([data]).setValues(opportunityUpdateCopy);
}
I've also tried getting the cell reference of the cells in the row with the corresponding OpportunityID and setting them with the values from the input sheet, but that hasn't worked either.
Any help or advice is much appreciated!
You need to use the nn value to select the range when there's a match, since nn is effectively your row index.
function updateOpportunity() {
// Get active spreadsheets and sheets
var ss = SpreadsheetApp.getActiveSpreadsheet();
var updateSheet = ss.getSheetByName("Update Sheet"); // You didn't have this defined, so I added
var inputSheet = ss.getSheetByName('Search & Create New Records');
var OppsAndContracts = ss.getSheetByName('Opportunities & Contracts');
var opportunityUpdateCopy = inputSheet.getRange('A8:Q8').getValues();
//Search for Opportunities using OpportunityID
var last = OppsAndContracts.getLastRow();
var data = OppsAndContracts.getRange(1,1,last,17).getValues(); // create an array of data from columns A through Q
var opportunityID = updateSheet.getRange("A8").getValue();
for (var nn = 0; nn < data.length; ++nn) {
if (data[nn][0] == opportunityID) {
OppsAndContracts.getRange(nn + 1, 1, 1, 17).setValues(opportunityUpdateCopy);
}
}
}
(I removed a bunch of the code that was irrelevant to your question.)
I have created a script to combine information from several tabs to a "master elements" tab. The script pull in rows tagged with the "MS" designation and it works great. However, I also want to pull in the Sheetname, Sheet IT, and possiby a link to the source tab for each row with "MS". That information is currently not stored in any of the source tabs. Is that possible to do in script?
function combineData() {
var destination = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Masterelements');
// TO CLEAR DESTINATION TAB BEFORE REPOPULATION
destination.getRange('A2:g1000').clearContent();
//VARIABLE TO CYCLE THROUGH SPECIFIC SHEETS
var tabs = [
'A-000',
'B-123',
];
var ss = SpreadsheetApp.getActiveSpreadsheet();
for (var s = 0; s < tabs.length; s++) {
var sheet = ss.getSheetByName(tabs[s]);
Logger.log(sheet.getLastRow());
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
var destination = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Masterelements');
var values = range.getValues();
//Destination parameters - equivalent to destination.getRange();
var numberOfColumns = 7;
var numberOfRows = 1;
var startColumn = 1;
var startRow = 2;
var count = 0
// IDENTIFY THE FIRST ROW TO CONSOLIDATE ITEMS
var destRow = destination.getLastRow() + 1
for (var i = 0; i < values.length; i++) {
Logger.log("i is now: " + i);
Logger.log("Current row value: " + values[i][0])
if (values[i][0] == 'MS') {
Logger.log("*** Value found in cloumn: " + values[i][0] + "**** \n Count: " + i);
count++;
var rangeToCopy = sheet.getRange((i + 1), 1, numberOfRows, numberOfColumns);
var destinationRange = destination.getRange(destRow, startColumn, numberOfRows, numberOfColumns);
destRow++;
Logger.log("Next Destination row: " + destRow);
rangeToCopy.copyTo(destinationRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}
}
}
}
The OP supplied working code that copies rows, from two specific sheets, with a value of "MS" in Column A. However the OP also wanted:
Sheetname
Sheet ID
possiby a link to the source tab for each row with "MS"
These are fairly easy to produce, but require too much information to explain in a comment.
I've taken the OP original code. I moved and/or edited some lines to make the code slightly more efficient. I've also added some lines of code to insert the Sheet name in Masterelements:Column H, the sheet ID in Masterelements:Column I and a link to the relevant sheet in Masterelements:Column J.
I think there is scope to make the code more efficient (specifically within the loops), but this is something that the OP can consider if the "real data" execution time is unreasonable.
function so54432164() {
// setup the spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get the spreadsheet URL - required for the hyperlink
var ssurl = ss.getUrl();
//Logger.log("DEBUG: The url for this spreadsheet is "+ssurl);//DEBUG
var destination = ss.getSheetByName('Masterelements');
// CLEAR DESTINATION TAB BEFORE REPOPULATION
// clear the entire destination sheet; this is more efficient that just clearing a nominated range
destination.clearContents();
// IDENTIFY THE first ROW TO CONSOLIDATE ITEMS
var destRow = destination.getLastRow() + 1
//VARIABLE TO CYCLE THROUGH SPECIFIC SHEETS
// note: no comma after the second tab name
var tabs = [
'A-000',
'B-123'
];
//Destination parameters
// note: brought this out of the "for" loop since only need to be declared once.
var numberOfColumns = 7;
var numberOfRows = 1;
var startColumn = 1;
var startRow = 2;
// used for destination.getRange();
// Loop through the sheets
for (var s = 0; s < tabs.length; s++) {
var sheet = ss.getSheetByName(tabs[s]);
// create variables to get the Sheet Name and the sheetID
var sheetname = sheet.getSheetName();
var sheetID = sheet.getSheetId();
//Logger.log("DEBUG: sheet: "+sheetname+", SheetID: "+sheetID);//DEBUG
// get the data: the var 'range' was never used, so we can just call the values direct to 'values'.
var values = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
//LOOP through the rows in the target sheet
for (var i = 0; i < values.length; i++) {
//Logger.log("DEBUG: row = " + i+", and Column A value: " + values[i][0]);//DEBUG
// test for "MS" in Column A
if (values[i][0] == 'MS') {
//Logger.log("DEBUG: Found MS, Count: " + i);//DEBUG
// define the range to copy
var rangeToCopy = sheet.getRange((i + 1), 1, numberOfRows, numberOfColumns);
// Logger.log("DEBUG: the rangetocopy is "+rangeToCopy.getA1Notation()); //DEBUG
// Define the destination range
var destinationRange = destination.getRange(destRow, startColumn, numberOfRows, numberOfColumns);
//Logger.log("DEBUG: the destination range "+destinationRange.getA1Notation());//DEBUG
// copy the source to the target
rangeToCopy.copyTo(destinationRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
// create a variable for the hyperlink formula
var formula = '=HYPERLINK("' + ssurl + '#gid=' + sheetID + '")';
// Logger.log("DEBUG: the formula = "+formula);//DEBUG
// create a variable for the extra data: Sheet name, Sheet ID, and the hyperlink to the sheet.
var extradata = [
[sheetname, sheetID, formula]
];
//define the destination range and set the values
destination.getRange(destRow, numberOfColumns + 1, numberOfRows, 3).setValues(extradata);
// increment the destination row
destRow++;
}
}
}
}