Looping through rows, get values, and add to total on another sheet - google-apps-script

So I'm stumped on this in Google Sheets.
Sheet 'Price Calculator' Qty has a of items bought and sold in Column A, separated into 2 named ranges TRADE_QTY and BUY_QTY.
An identical List appears in sheet 'Master Tally', with qtys from previous trades, also in column A.
Have been flipping through multiple windows of examples of code and none seem to be able to provide anything that works.
function TEST() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
//Gets number of rows of each range
var Rows1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getNumRows()
var Rows2 = ss.getRange('\'PRICE CALCULATOR\'!BUY_QTY').getNumRows()
//Gets Starting rows of each range
var Row1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getRow()
var Row2 = ss.getRange('\'PRICE CALCULATOR\'!BUY_QTY').getRow()
for (r=Row1; r<Rows1; r++) {
ss.setActiveSheet(ss.getSheetByName('PRICE CALCULATOR'), true);
var ADD = ss.getRange(r,1).getValue()
if (cell.isBlank()) {
next r
}
else {
ss.setActiveSheet(ss.getSheetByName('Master Tally'), true);
var EXIST = ss.getRange(r,1).getValue()
var TOT = ADD+EXIST
ss.getRange(r,1).setValue(TOT)
}
}
}
Basically i'm try to develop a macro/script that adds the new trade qtys in sheet 'Price Calculator' to the existing qtys in 'Master Tally'
I"m stumped as it keeps throwing me 'Cannot find method getRange(number,number)' and now i'm out of my depth!
Link to the document;
https://docs.google.com/spreadsheets/d/1gIjCqv5KT41wYuJS1Hs1X8yPPUTPY_kGoTuilzxLkSo/edit?usp=sharing

This code suffers from a basic flaw: confusion between Row and Column numbers of an array (which start at 0-zero) with those derived from script commands such as getValue (which start at 1-one).
For example:
for (r=Row1; r<Rows1; r++) {
In this case, the value of Row1 was determined by getRow, so it returns the actual row number. But the loop values will generate the row and column number for an array starting at zero; so this line should read for (r=0; r<Rows1; r++) {
var EXIST = ss.getRange(r,1).getValue()
The purpose of this line is return the "existing qtys in 'Master Tally'", and the range will look in Column A for the value. However the values are actually in column B. So this line will never return an accurate value for "existing qtys".
There are some other things to note:
The existing code makes two getValue calls in every loop; these are time-expensive. The answer improves performance by getting the respective range values just once before the loop.
The update of the quantity sold (setValue(TOT)) is inside the loop. Again this is a time-expensive command. The answer updates the array values within the loop, and then updates the sheet once-only after the loop.
BUY Qty values are irrelevant
function so56017521() {
var ss = SpreadsheetApp.getActive();
//Gets number of rows of each range
var Rows1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getNumRows()
//Logger.log("DEBUG: Number of Rows: Trade Qty="+Rows1);
//Gets Starting rows of each range
var Row1 = ss.getRange('\'PRICE CALCULATOR\'!TRADE_QTY').getRow()
//Logger.log("DEBUG: Start Row: Trade Qty="+Row1);
// setup sheets
var calcsheet = "PRICE CALCULATOR";
var mastersheet = "Master Tally";
var calc = ss.getSheetByName(calcsheet);
var master = ss.getSheetByName(mastersheet);
var masterrows = master.getLastRow();
//Logger.log("DEBUG: Master Last Row = "+masterrows);
// get data for each sheet
var calcrange = calc.getRange(Row1, 1, Rows1);
var calcdata = calcrange.getValues();
var masterrange = master.getRange(3, 2, masterrows - 2);
var masterdata = masterrange.getValues();
//Logger.log("DEBUG: Calc data range = "+calcrange.getA1Notation()+", Master Data Range"+masterrange.getA1Notation());
for (r = 0; r < Rows1; r++) {
Logger.log("r=" + r);
var ADD = calcdata[r][0]; //Trade qty
//Logger.log("DEBUG: r="+r+", ADD value = "+ADD+", ADD.length = "+ADD.toString().length);
if (ADD.toString().length != 0) { // if Trade qty has value
// keep going
//Logger.log("DEBUG: keep going");
var EXIST = masterdata[r][0]; // existing quantity qty sold
Logger.log("DEBUG: r=" + r + ", EXIST = " + EXIST);
var TOT = ADD + EXIST; // sum of trade-in qty plus existing qty
Logger.log("DEBUG: ADD+EXIST = " + TOT);
// update masterdata array
masterdata[r][0] = TOT;
} else {
// nothing to see here
//Logger.log("DEBUG: next r please");
}
}
//update the spreadsheet with the adjusted array values
masterrange.setValues(masterdata);
}

Related

Google app script for loop is extremely slow

I have a pivot table set up in a google sheet file where I've labeled the sheet pivot table 1. I want to get each value of the first column of the pivot, duplicate each values 12 times in an array and paste these values in the 3rd column of sheet 5. However, it seems extremely slow to do with the script never really completing (just takes 10+ minutes before I've cancelled it).
The pivot has approximately 3000 lines, which would result in a 3000 * 12 = 36000 array.
Any thoughts on how I can optimize this?
function test2() {
// activating current spreadsheet for use
var spreadsheet = SpreadsheetApp.getActive();
//empty array
var array_dept = []
// returns (integer #) the last row of the pivot table 1 sheet that has content
var last_row = spreadsheet.getSheetByName("Pivot Table 1").getLastRow();
// Get value in pivot table 1 from range of row 1 (dept name), column 1, all the way to last row
// Then paste it in sheet5 from row 1, column 3, all the way to the last row defined above
for (var i = 1; i < last_row; i++ )
{
//get value and then paste it in a destination
var value_dept = spreadsheet.getSheetByName("Pivot Table 1").getRange(i,1).getValue();
array_dept.fill(value_dept, -12 + (12*i) , 12*i)
}
destination_dept = spreadsheet.getSheetByName("Sheet5").getRange(1,3, last_row);
destination_dept.setValues(array_dept);
}
You don't need use a loop if you know the first row and the last row on the source column. You can just define the range:
var pivotRange = pivot.getRange(1,1,last_row)
var targetRange = target.getRange(1,3,last_row)
doc ref; this is just one of five methods to define a range.
In the OP script, there would be 3000xgetRange + 3000xgetValue. In this answer there are: 2xgetRange and 1 x getValue. This should account for a substantial amount of script processing. Of course, we know nothing of the rest of the spreadsheet (its size, formula, functions, triggers, etc). But all other things being equal, this should improve the performance of the script.
function test2() {
// activating current spreadsheet for use
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var pivotSheetName = "Pivot Table 1"
var pivot = spreadsheet.getSheetByName(pivotSheetName)
//temporary array
var array_dept = []
// returns (integer #) the last row of the pivot table 1 sheet that has content
var last_row = pivot.getLastRow();
//Logger.log("DEBUG: last row in the pivot table:"+last_row)
var pivotRange = pivot.getRange(1,1,last_row)
// Logger.log("DEBUG: the range for the pivot range = "+pivotRange.getA1Notation())
var pivotData = pivotRange.getValues()
//Then paste it in sheet5 from row 1, column 3, all the way to the last row defined above
var targetSheetName = "Sheet5"
var target = spreadsheet.getSheetByName(targetSheetName)
var targetRange = target.getRange(1,3,last_row)
// Logger.log("DEBUG: the range for the target range = "+targetRange.getA1Notation())
targetRange.setValues(pivotData)
Logger.log("Done")
}

Exception: The number of columns in the data does not match the number of columns in the range. The data has 0 but the range has 1

I am very new to javascript and have searched around a ton for this and can't seem to find the issue with my code. I am attempting to simply write a code that will copy the values in a column from a pivot table sheet in Google Sheet and then paste the values in another sheet. However, before pasting the values, I want each individual value to be duplicated 12 times (for 12 months). So, assuming I have 10 unique values (A, B, C, D, E, F, G, H, I, J) that I am copying, I want to return value A 12 times in a row, then value B 12 times in a row, etc.
I run getValues, which seems to put the values in a 2 dimensional array. I've then taken this temp_array that I had created and used a for loop to duplicate each value 12 times in a new array.
However, when I setValues, I am pasting the values in my spreadsheet correctly, but I get this error message regardless (The number of columns in the data does not match the number of columns in the range. The data has 0 but the range has 1.), any ideas why?
Here is a small example of what my input could look like (1st image) and what I would want the output to look like (2nd image)
function test2() {
// activating current spreadsheet for use
var spreadsheet = SpreadsheetApp.getActive();
//empty array
var array_dept_temp = [];
// returns cell position (ex: C5) of the last row of the pivot table 1 sheet that has content in column 1
var last_row = spreadsheet.getSheetByName("Pivot Table 1").getRange("A:A").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRowIndex();
//subtracting 1 from last row because we are excluding the headers. This gives us our row_length
var row_length = last_row - 1
var array_dept = [[]]
array_dept = new Array(row_length*12)
//new Array(row_length*12);
// Get value in pivot table 1 from range of row 2 (dept name, but exclude the header), column 1, all the way to last row
// Then paste it in sheet5 from row 1, column 3, all the way to the last row defined above
array_dept_temp = spreadsheet.getSheetByName("Pivot Table 1").getRange(2,1, last_row).getValues();
for (var i = 1; i < row_length; i++ )
{
//get value and then paste it in a destination
array_dept.fill(array_dept_temp[i-1], (-12 + (12*i)) , 12*i);
}
var destination_dept = spreadsheet.getSheetByName("Sheet5").getRange(2,3,row_length*12);
destination_dept.setValues(array_dept);
}
Suggestion / Alternate solution:
Try:
function test() {
  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = spreadsheet.getSheetByName("Pivot Table 1");
  var array_dept_temp = sheet.getRange(2,1, sheet.getLastRow()-1).getValues();
  var array_dept = [];
  for (var i = 0; i < array_dept_temp.length; i++) {
    array_dept = [...array_dept, ...Array.apply(null, Array(12)).map(function(){return array_dept_temp[i]})]
  }
  var destination_dept = spreadsheet.getSheetByName("Sheet5").getRange(2,3,array_dept.length);
  destination_dept.setValues(array_dept);
}
Result:
Another way without using fill or from.
Also some modification, you can just use .getLastRow() function to get the last row, however take not that if there is data below it will count all the rows including the blank until the row that has data. And you may also use .length on your data to setValue.
From your showing sample input and output situations, how about the following modified script?
Modified script:
function test2_sample() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = ss.getSheetByName("Pivot Table 1");
var dstSheet = ss.getSheetByName("Sheet5");
var srcValues = srcSheet.getRange("A2:A" + srcSheet.getLastRow()).getValues();
var dstValues = srcValues.flatMap(a => Array(12).fill(a));
dstSheet.getRange(2, 3, dstValues.length).setValues(dstValues);
}
When this script is run using your sample input sheet, I think that your expected output values are obtained.
Now, I thought that var dstValues = srcValues.flatMap(([a]) => Array(12).fill(a).map(e => [e])); can be modified to var dstValues = srcValues.flatMap(a => Array(12).fill(a));. This is simpler.
From your reply of Are you able to explain what this does? var dstValues = srcValues.flatMap(([a]) => Array(12).fill(a).map(e => [e]));, in this script, var dstValues = srcValues.flatMap(([a]) => Array(12).fill(a).map(e => [e])); can be also modified as follows. I thought that this might also help to understand it.
function test2_sample() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = ss.getSheetByName("Pivot Table 1");
var dstSheet = ss.getSheetByName("Sheet5");
var srcValues = srcSheet.getRange("A2:A" + srcSheet.getLastRow()).getValues();
var dstValues = [];
for (var i = 0; i < srcValues.length; i++) {
dstValues = dstValues.concat(Array(12).fill(srcValues[i]));
}
dstSheet.getRange(2, 3, dstValues.length).setValues(dstValues);
}
Note:
As additional information, when your showing script is modified, how about the following modification? In your script, I thought that it is required to add the values to array_dept in the loop. And, it is required to flatten the elements in the array.
function test2() {
var spreadsheet = SpreadsheetApp.getActive();
var array_dept_temp = [];
var last_row = spreadsheet.getSheetByName("Pivot Table 1").getRange("A:A").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRowIndex();
var row_length = last_row - 1
var array_dept = []
array_dept_temp = spreadsheet.getSheetByName("Pivot Table 1").getRange(2, 1, last_row).getValues();
for (var i = 0; i < row_length; i++) {
array_dept = [...array_dept, ...Array(12).fill(array_dept_temp[i])];
}
var destination_dept = spreadsheet.getSheetByName("Sheet5").getRange(2, 3, array_dept.length);
destination_dept.setValues(array_dept);
}
Reference:
flatMap()

I have a GAS script to copy a range of cells from one sheet to another the data inserts correctly, but also adds two additional blank rows

My users can enter new products on a separate sheet for review from the buyer. If accepted, the buyer then runs the script from the menu.
The process works perfectly, copying the new information into the price book and then clearing the data from the New Item sheet. But, the process seems to always add two blank cells, even though there are no extra rows in either sheet.
function addNewItems() {
//Get new item data from New Items Sheet
var ss = SpreadsheetApp.getActive();
var s = ss.getSheetByName("New Items");
s.activate();
//define non-contiguous data ranges from source sheet fpr clearing after copying
var newInput1 = ss.getRange("New Items!A2:K");
var newInput2 = ss.getRange("New Items!N2:O");
var newInput3 = ss.getRange("New Items!Q2:R");
// Get last row of data from source sheet
lastR = s.getLastRow();
// Select range of data with new item information (17 is the last column of data)
var newItems = s.getRange(2,1,lastR,17).getValues();
//Switch to target sheet to add new records into Price Book
var ts = ss.getSheetByName("Price Book");
ts.activate();
//Find last row of Price Book data and add one to get next row
tsIns = ts.getLastRow();
//Start at the next row and insert the data range from the New Item sheet
var newInsert = ts.getRange(tsIns +1,1,lastR,17).setValues(newItems);
//Clear data from new item sheets after copying data to the Price Book
newInput1.clearContent();
newInput2.clearContent();
newInput3.clearContent();
}
Try this:
function addNewItems() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("New Items");
let lastR = sh.getLastRow();
var newInput1 = sh.getRange("A2:K" + lastR);
var newInput2 = sh.getRange("N2:O" + lastR);
var newInput3 = sh.getRange("Q2:R" + lastR);
var newItems = sh.getRange(2, 1, lastR - 1, 17).getValues();
var tsh = ss.getSheetByName("Price Book");
tsIns = tsh.getLastRow();
tsh.getRange(tsIns + 1, 1, lastR - 1, 17).setValues(newItems);
newInput1.clearContent();
newInput2.clearContent();
newInput3.clearContent();
}
I don't know about 2, but definitely 1. In getRange, the third parameter is number of rows to get or set. Since you getValues() starting at row 2 you should subtract 1 from lastR since its value is the total number of rows with values including the headers.
Therefore you should change the following 2 lines of code as shown.
var newItems = s.getRange(2,1,lastR-1,17).getValues();
var newInsert = ts.getRange(tsIns +1,1,lastR-1,17).setValues(newItems);

How to delete cells if no match was found?

I'm having difficulties writing the IF statement to satisfy my condition. I have 2 sheets: Main and Logistics. The first one has specific information about cargo and it's transportation, such as trailer, position and arrival date. The second sheet contains all of the transportation information, such names of the trailer, drivers, arrivals, departures etc. Based on the scheduled trailers on sheet "Logistics", the user can specify which of the available trailers he wants to use for the cargo in question.
However, in a situation when the trailer gets deleted from "Logistics" due to a cancellation, I am unable to revoke previously made selection on "Main". My idea is to make this script look for matching combinations of Destination and Trailer on both sheets (columns 8 and 13 on Main, columns 1 and 2 on Logistics). If there is a row on "Main" for which no matching trailer with the same destination was found on "Logistics", the script should set columns 13, 14 and 16 on "Main" to empty.
Could someone help me write an IF statement to satisfy this condition?
I have attached the bit of code I have so far. I think only IF statement needs modifying. Thanks for the help!
function deleteSelection() {
// Main variables:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetMain = ss.getSheetByName("Main");
var tabMain = sheetMain.getRange(2, 1, sheetMain.getLastRow(), 18);
var dataMain = tabMain.getValues();
// Logistics variables:
var sheet = ss.getSheetByName("Logistics");
var dataRange = sheet.getRange(2, 1, sheet.getLastRow(), 9);
var data = dataRange.getValues();
for(var i = 0; i < dataMain.length; i++){
for(var j = 0; j < data.length; j++){
// Compare data: if there is no match between 2 sheets, set "Trailer", "Position" and "Arrival date" to empty:
if(dataMain[i][7].toLowerCase() == data[j][0].toLowerCase() && dataMain[i][12] == data[j][1]){
} else{
dataMain[i][12] = "";
dataMain[i][13] = "";
dataMain[i][15] = "";
}
}
}
// Take the modified tab and put it on the spreadsheet
tabMain.setValues(dataMain);
}
UPD: Added a sample link. On "Logistics" you can see crossed out row, upon delete of which, a script should delete crossed out rows on "Main".
You are trying to establish whether the Event and Trailer values on Main match a value on Logistics.
I have taken a slightly different approach to you. I concatenated the value of the Main "EVent" and "Trailer" and used that value to find the match on Logistics.
If a Match is found, then the script can break out of that loop and proceed to the next loop.
If no Match is found, then a variable is incremented (since the match may be found in a subsequent comparison). However, once all the values on Logistics have been evaluated, if the number of mismatches is equal to the number of records on Logistics, then the values on Main must be updated.
function so5992862301() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetMain = ss.getSheetByName("Main");
var tabMain = sheetMain.getRange(2, 1, sheetMain.getLastRow()-1, 18);
var dataMain = tabMain.getValues();
// Logger.log("DEBUG: Last row = "+sheetMain.getLastRow()+", length of dataMain = "+dataMain.length+" tab main = "+tabMain.getA1Notation());
// Logistics variables:
var sheet = ss.getSheetByName("Logistics");
var dataRange = sheet.getRange(2, 1, sheet.getLastRow()-1, 9);
var data = dataRange.getValues();
// Logger.log("DEBUG: Logistics Last row = "+sheet.getLastRow()+", length of data = "+data.length+" dataRange = "+dataRange.getA1Notation());
// start loop through Main
for(var i = 0; i < dataMain.length; i++){
// count the matches
var mismatch=0
// start loop through Logistics
for(var j = 0; j < data.length; j++){
// match Logistics: Event (Column A) and Trailer (Column B)
// match Main: Event (Column A) and Trailer (Column C)
// Compare data: if there is no match between 2 sheets, set "Trailer", "Position" and "Arrival date" to empty:
var logEventTrailer = data[j][0]+data[j][1];
var mainEventTrailer = dataMain[i][0]+dataMain[i][2];
//Logger.log("DEBUG: i:"+i+", Main:"+mainEventTrailer+", j:"+j+" Log:"+logEventTrailer);
if (mainEventTrailer === logEventTrailer){
// match
// Logger.log("DEBUG: Match-"+"i:"+i+", Main:"+mainEventTrailer+", j:"+j+" Log:"+logEventTrailer);
// if this is a match, then break loop and goto to next i
break;
}
else{
// no match
mismatch = mismatch+1
//Logger.log("DEBUG: No match:"+match+"-i:"+i+", Main:"+mainEventTrailer+", j:"+j+" Log:"+logEventTrailer)
}
// how many mismatches
if (mismatch ==data.length){
// no match found
//Logger.log("DEBUG: no match found");
// update array values for this row
dataMain[i][2] = "";
dataMain[i][3] = "";
dataMain[i][4] = "";
}
}
}
// update the array values for Main
tabMain.setValues(dataMain);
}

I am trying to write a program where it the inputs from a google form will match with a list in spreadsheet,and add the quantities together

I am trying to match 2 variables(one taken from form submission and one is in the data base),and then add their quantities together. Is there any tips or advise on it?
Initially I tried doing it the opposite way. Which was having the list(over 2000 things) search the data from form submissions and then add it together. I realize that it will be too laggy that way,thus this solution,but i have no idea how I can start on it.
if(input1 == database1){
var qty_database1 = qty_database1 + qty_input1 ;
}
if(input1 == database2){
var qty_database2 = qty_database2 + qty_input1 ;
}
By doing this way,I will have to make each of the 35 inputs(all from form submission,not all 35 might have values) check against 2000+ variables(taken from the data base),which is not effective.I tried searching around on the web but cant seem to find what i need.
Here is the link :Spreadsheet of data collected
"Total Defects by departments" is the database,where all information will be stored.
The other tabs are all 3 form submissions spreadsheets.
If there is a similar "S No." & "ID No." in the 1st/2nd/3rd AQL,it will only take the last set of values,in the order of 3rd,2nd & lastly 1st.
The following answer may seem unduly long but the two key lines are:
var defectcodes = defectvalues.map(function (row) { return row[0]; });
var c = defectcodes.indexOf(respcode);
The OP receives form submissions reporting defects. There are three forms, and each response can include information for up to 35 separate defects. Defect information comprises six fields, but for the sake of this exercise there are three key fields: "department", "defect type" and the number of defects. The OP's goal is to report defect information, in a separate sheet ("Total Defects"), showing the total number of defects for each department/defect combination. There are over 2,100 department/defect combinations arranged in five sets of three columns (Department, Defect and Qty).
The OP's problem is the matching of the "department" and "defect" from the form responses sheets.
There are several elements essential to this proposed solution:
Change the layout of the "Total Defects" sheet.
The five column-set layout is an unnecessary complication. The layout should be simplified into a single column-set of 2100 rows.
Simplify the search/match.
Instead of matching two separate values ("Department" and "Defect"), create a single unique code by concatenating those values, and use this for the search/match.
Use the Javascript methods of 'map' and 'indexof' to simplify processing.
In the following answer, I have focused on the essentials of the solution. I have not added code to automatically loop through the three form response sheets, nor to update the quantity; these are red herrings. I have left a number of Logger statements in the code to assist the OP (and others) in troubleshooting and/or understanding the code.
function so5652371304() {
// setup Defects spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "TotalDefects02";
var defectsheet = ss.getSheetByName(sheetname);
//Logger.log("DEBUG: Defect sheet name "+defectsheet.getName());//DEBUG
var defectlastrow = defectsheet.getLastRow();
//Logger.log("DEBUG: the last defect row = "+defectlastrow);//DEBUG
// Layout on Total Defects is:
// Row#1 = Header
// Column A = Department
// Column B = Defect
// Column C = Concatenate Column A and Column B
// Column D = Qty
var defectrange = defectsheet.getRange(2,3,defectlastrow-1);// column 3 (C)- dept+code
//Logger.log("DEBUG: the defect range is "+defectrange.getA1Notation());//DEBUG
var defectvalues = defectrange.getValues();
// apply the "map" method to assign the row number to every element
var defectcodes = defectvalues.map(function (row) { return row[0]; });
// set up the response sheets
var respsheetname = "1st AQL";// 1st AQL// 2nd AQL // 3rd AQL
var respsheet = ss.getSheetByName(respsheetname);
//Logger.log("DEBUG: Response sheet name "+respsheet.getName());//DEBUG
var resplastrow = respsheet.getLastRow();
var resplastcolumn = respsheet.getLastColumn();
//Logger.log("DEBUG: Response lastrow = "+resplastrow+", last column"+resplastcolumn); //DEBUG
// Layout on Total Defects is:
// Row#1 & 2 = Header
// Column A to Q (Inclusive) = Irrelevant information (Column 1 to 17 inclusive)
// Column R to W = Response dataset#1
// Column R (18) = Department#1
// Column S (19) = Defect#1
// Column T (20) = Quantity
// Column U (21) = Irrelevant
// Column V (22) = Irrelevant
// Column W (23) = Irreelvant
// Column X (24) to HR (226) consists of a further 34 possible defect notices, each of 6 columns
var resprange = respsheet.getRange(3,18,resplastrow-2,resplastcolumn-18+1);
//Logger.log("DEBUG: the resp range is "+resprange.getA1Notation());//DEBUG
var respvalues = resprange.getValues();
// set Response variables
var repliesperrow=35;
var columnsperreply = 6;
//Loop through replies to find matches in the database
for (var r = 0;r<resplastrow-2;r++){//loop rows
for (var i=0; i<repliesperrow;i++){//loop per reply
if (respvalues[r][(i*columnsperreply)].length>0){
//Logger.log("DEBUG: dept = "+respvalues[r][(i*columnsperreply)]+", defect = "+respvalues[r][((i*columnsperreply)+1)]+", qty = "+respvalues[r][(i*columnsperreply)+2]); //DEBUG
var respcode = respvalues[r][(i*columnsperreply)].concat('',respvalues[r][((i*columnsperreply)+1)]);
var c = defectcodes.indexOf(respcode);
// if c=-1 then the code is not in TotalDefects Table
// if c>-1 then the code IS in the TotalDefects Table, AND the relevant row number of the matching code = c+2
if (c > -1) {
Logger.log("DEBUG: r:"+r+", i:"+i+", c="+c+", Code:"+respcode+" found in the defects database on row:"+(c+2)); // DEBUG the details are on (c+2) rows
} else {
Logger.log("DEBUG: r:"+r+", i:"+i+", c="+c+", Code:"+respcode+" NOT found in the defects database"); //DEBUG
}
}
else{
continue;
}
}
}
}
Layout-TotalDefects sheet
UPDATE:
This revision loops through the sheets, and updates the Total Defects quantity. Rather than using (the expensive) setValue() for each new quantity value, the code accumulates the qty value and then writes a single setValues at the end of each response sheet.
Note that there are Logger statements that can be displayed for:
Successful responses
Unsuccessful responses (where the concatenated code could not be found in Total Defects. One might suggest to the OP that these should be written to an error sheet to simplify troubleshooting.
function so5652371306() {
// setup Defects spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "TotalDefects06";
var defectsheet = ss.getSheetByName(sheetname);
//Logger.log("DEBUG: Defect sheet name "+defectsheet.getName());//DEBUG
var defectlastrow = defectsheet.getLastRow();
//Logger.log("DEBUG: the last defect row = "+defectlastrow);//DEBUG
// Layout on Total Defects is:
// Row#1 = Header
// Column A = Department
// Column B = Defect
// Column C = Concatenate Column A and Column B
// Column D = Qty
// get 2 x ranges and data
// defectrange = enables the code to access the existing value of the qty
var defectrange = defectsheet.getRange(2,3,defectlastrow-1,2);// column C - dept+code // column D = qty
//Logger.log("DEBUG: the defect range is "+defectrange.getA1Notation());//DEBUG
var defectvalues = defectrange.getValues();
// defectqtyrange = enables the code to increment the qty andf then, as the last command, paste the adjusted values back onto the spreadsheet
// this avoids setValue within the Response loops.
var defectqtyrange = defectsheet.getRange(2,4,defectlastrow-1,1);// column D - qty
var defectqtyvalues = defectqtyrange.getValues();
// apply the "map" method to assign the row number to every element
var defectcodes = defectvalues.map(function (row) { return row[0]; });
// set up an array of response sheets
var respsheetname = [
'1st AQL',
'2nd AQL',
'3rd AQL'
];
// Layout of Response Sheets is:
// Row#1 & 2 = Header
// Column A to Q (Inclusive) = Irrelevant information (Column 1 to 17 inclusive)
// Column R to W = Response dataset#1
// Column R (18) = Department#1
// Column S (19) = Defect#1
// Column T (20) = Quantity
// Column U (21) = Irrelevant
// Column V (22) = Irrelevant
// Column W (23) = Irreelvant
// Column X (24) to HR (226) consists of a further 34 possible defect notices, each of 6 columns
// set Response variables
var repliesperrow = 35;
var columnsperreply = 6;
// loop through the response sheets
for (var t = 0; t < respsheetname.length; t++) {
var respsheet=ss.getSheetByName(respsheetname[t]);
var thissheet = respsheet.getName();
// Logger.log("DEBUG: Response sheet name "+thissheet);//DEBUG
var resplastrow = respsheet.getLastRow();
var resplastcolumn = respsheet.getLastColumn();
//Logger.log("DEBUG: Response lastrow = "+resplastrow+", last column"+resplastcolumn); //DEBUG
// define the range
var resprange = respsheet.getRange(3,18,resplastrow-2,resplastcolumn-18+1);
//Logger.log("DEBUG: the resp range is "+resprange.getA1Notation());//DEBUG
// get the response data
var respvalues = resprange.getValues();
//Loop through replies to find matches in the database
for (var r = 0;r<resplastrow-2;r++){//loop rows
for (var i=0; i<repliesperrow;i++){//loop per reply
if (respvalues[r][(i*columnsperreply)].length>0){
var respcode = respvalues[r][(i*columnsperreply)].concat('',respvalues[r][((i*columnsperreply)+1)]);
var c = defectcodes.indexOf(respcode);
// if c=-1 then the code is not in TotalDefects Table
// if c>-1 then the code IS in the TotalDefects Table, AND the relevant row number of the matching code = c+2
if (c > -1) {
// display this for the successful matches
//Logger.log("DEBUG: RESPONSE FOUND IN THE DATABASE. \nSheet:"+thissheet+", response row:"+(+r+1)+", response#:"+(+i+1)+", indexOf:"+c+", Code:"+respcode+", Qty:"+respvalues[r][(i*columnsperreply)+2]); // DEBUG the details are on (c+2) rows
// display this for matching row in the Total Defects
//Logger.log("DEBUG: Corresponding Defect. Code:"+defectvalues[c][0]+", Qty:"+defectvalues[c][1]+", SpreadsheetRow:"+(+c+2));
// increment the adjusted Total Defect quantity
defectqtyvalues[c][0] = Number(defectqtyvalues[c][0])+Number(respvalues[r][(i*columnsperreply)+2]);
} else {
// display this for failed matches
// Logger.log("DEBUG: Response: Code not found in Total Defects. \nSheet:"+thissheet+", response row:"+(+r+1)+", response#:"+(+i+1)+", Code:"+respcode); //DEBUG
}
}
else{
continue;
}
}
}
// update the defect range with the adjusted qty
defectqtyrange.setValues(defectqtyvalues);
}
}
It sounds like you just want a pivot table of the values in your form responses. Try highlighting your data, and go to data > pivot table, and play with it there. I don't think you want a scripted function here at all.