Vlookup or Indexing using google apps scripts - google-apps-script
I have a spreadshseet (Sheet1) in which the Data is there from Col A to Column D, and in another sheet (Sheet1), again the data is there from Col A to Col W, in which the Col F data has some matching with column D.
What i am seeking for:
I want to pull data from Sheet2 (from Col F onwards, i.e. G, H, I etc.) in Col E and so on in Sheet1.
Sheet2
Col
F G H I J K L
1 A B C D E F
2 a1 b1 c1 d1 e1 f1
3 a2 b2 c2 d2 e2 f2
and so on
Sheet1
Col D E F G H
1 A B C D
3 a2 b2 c2 d2
Data to reflect in col E,F,G H in sheet1 from sheet2 against column D in col E,F, either using vlookup, or indexing.
What i tried but in Vain
http://productforums.google.com/forum/#!topic/apps-script/HzeNdIqnIUc
I want to use only google apps only to get the desired results.
Requesting for help on this.
Regards
I'm sorry you're having a problem with your VLOOKUP but it's a Google Spreadsheets user question not a stackoverflow (programming) question. It might help you to know these things:
You're on the right track with VLOOKUP. The spreadsheet function VLOOKUP definitely works for getting data in sheet2 to lookup based on keys/columns in sheet1. It works really well for what you say you need to do.
You can search the Google support site: http://support.google.com/docs/bin/search.py?query=vlookup
You can ask in the Google Docs Help forum https://productforums.google.com/forum/#!forum/docs
Good luck.
Its an old article but others may still stumble across it.
Here is something I wrote to address my Vlookup Needs in script form.
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on isEmpty_()
// Script Look-up
/*
Benefit of this script is:
-That google sheets will not continually do lookups on data that is not changing with using this function as it is set with hard values until script is kicked off again.
-Unlike Vlookup you can have it look at for reference data at any Column in the row. Does not have to be in the first column for it to work like Vlookup.
-You can return the Lookup to Memory for further processing by other functions
Useage:
var LocNum = SpreadsheetApp.openById(SheetID).getSheetByName('Sheet1').getRange('J2:J').getValues();
Lookup_(Sheetinfo,"Sheet1!A:B",0,[1],"Sheet1!I1","n","y");
//or
Lookup_(Sheetinfo,"Sheet1!A:B",0,[1],"return","n","n");
//or
Lookup_(Sheetinfo,"Sheet1!A:B",0,[0,1],"return","n","n");
//or
Lookup_(Sheetinfo,"Sheet1!A:B",1,[0],"return","y","n");
//or
Lookup_(Sheetinfo,"Sheet1!A:G",4,[0],"Database!A1","y","y");
*/
function Lookup_(Search_Key,RefSheetRange,SearchKey_Ref_IndexOffSet,IndexOffSetForReturn,SetSheetRange,ReturnMultiResults,Add_Note)
{
var RefSheetRange = RefSheetRange.split("!");
var Ref_Sheet = RefSheetRange[0];
var Ref_Range = RefSheetRange[1];
if(!/return/i.test(SetSheetRange))
{
var SetSheetRange = SetSheetRange.split("!");
var Set_Sheet = SetSheetRange[0];
var Set_Range = SetSheetRange[1];
var RowVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Range).getRow();
var ColVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Range).getColumn();
}
var twoDimensionalArray = [];
var data = SpreadsheetApp.getActive().getSheetByName(Ref_Sheet).getRange(Ref_Range).getValues(); //Syncs sheet by name and range into var
for (var i = 0, Il=Search_Key.length; i<Il; i++) // i = number of rows to index and search
{
var Sending = []; //Making a Blank Array
var newArray = []; //Making a Blank Array
var Found ="";
for (var nn=0, NNL=data.length; nn<NNL; nn++) //nn = will be the number of row that the data is found at
{
if(Found==1 && ReturnMultiResults.toUpperCase() == 'N') //if statement for found if found = 1 it will to stop all other logic in nn loop from running
{
break; //Breaking nn loop once found
}
if (data[nn][SearchKey_Ref_IndexOffSet]==Search_Key[i]) //if statement is triggered when the search_key is found.
{
var newArray = [];
for (var cc=0, CCL=IndexOffSetForReturn.length; cc<CCL; cc++) //cc = numbers of columns to referance
{
var iosr = IndexOffSetForReturn[cc]; //Loading the value of current cc
var Sending = data[nn][iosr]; //Loading data of Level nn offset by value of cc
if(isEmpty_(Sending)) //if statement for if one of the returned Column level cells are blank
{
var Sending = "#N/A"; //Sets #N/A on all column levels that are blank
}
if (CCL>1) //if statement for multi-Column returns
{
newArray.push(Sending);
if(CCL-1 == cc) //if statement for pulling all columns into larger array
{
twoDimensionalArray.push(newArray);
var Found = 1; //Modifying found to 1 if found to stop all other logic in nn loop
break; //Breaking cc loop once found
}
}
else if (CCL<=1) //if statement for single-Column returns
{
twoDimensionalArray.push(Sending);
var Found = 1; //Modifying found to 1 if found to stop all other logic in nn loop
break; //Breaking cc loop once found
}
}
}
if(NNL-1==nn && isEmpty_(Sending)) //following if statement is for if the current item in lookup array is not found. Nessessary for data structure.
{
for(var na=0,NAL=IndexOffSetForReturn.length;na<NAL;na++) //looping for the number of columns to place "#N/A" in to preserve data structure
{
if (NAL<=1) //checks to see if it's a single column return
{
var Sending = "#N/A";
twoDimensionalArray.push(Sending);
}
else if (NAL>1) //checks to see if it's a Multi column return
{
var Sending = "#N/A";
newArray.push(Sending);
}
}
if (NAL>1) //checks to see if it's a Multi column return
{
twoDimensionalArray.push(newArray);
}
}
}
}
if (CCL<=1) //checks to see if it's a single column return for running setValue
{
var singleArrayForm = [];
for (var l = 0,lL=twoDimensionalArray.length; l<lL; l++) //Builds 2d Looping-Array to allow choosing of columns at a future point
{
singleArrayForm.push([twoDimensionalArray[l]]);
}
if(!/return/i.test(SetSheetRange))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,singleArrayForm.length,singleArrayForm[0].length).setValues(singleArrayForm);
SpreadsheetApp.flush();
if(/y/i.test(Add_Note))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,1,1).setNote("VLookup Script Ran On: " + Utilities.formatDate(new Date(), "PST", "MM-dd-yyyy hh:mm a") + "\nRange: " + Ref_Sheet + "!" + Ref_Range);
}
}
else
{
return singleArrayForm
}
}
if (CCL>1) //checks to see if it's a multi column return for running setValues
{
if(!/return/i.test(SetSheetRange))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,twoDimensionalArray.length,twoDimensionalArray[0].length).setValues(twoDimensionalArray);
SpreadsheetApp.flush();
if(/y/i.test(Add_Note))
{
SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,1,1).setNote("VLookup Script Ran On: " + Utilities.formatDate(new Date(), "PST", "MM-dd-yyyy hh:mm a") + "\nRange: " + Ref_Sheet + "!" + Ref_Range);
}
}
else
{
return twoDimensionalArray
}
}
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
// Empty String Check
function isEmpty_(string)
{
if(Object.prototype.toString.call(string) == '[object Boolean]') return false;
if(!string) return true;
if(string == '') return true;
if(string === false) return true;
if(string === null) return true;
if(string == undefined) return true;
string = string+' '; // check for a bunch of whitespace
if('' == (string.replace(/^\s\s*/, '').replace(/\s\s*$/, ''))) return true;
return false;
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
Related
SOLVED - Copy row between Google Sheets using Google script
I need some help because I have zero knowledge of Google App Script programming language and I'm not able to solve this problem; I searched the solution on different forums and I watched a lot of different videos on YouTube but I was not able to change the code as I need. I'm combining Google Script with MIT App Inventor (this is the page from which I copied the code: https://ai2.metricrat.co.uk/guides/google-sheet-crudq-ii) and I need to change the "DELETE" function (the last one) to copy the row to delete into another sheet (called ORP_completati) in the same Google Sheet function doGet(e) { var ss = SpreadsheetApp.openById(e.parameter.ID); var sh = ss.getSheetByName(e.parameter.SH); var logSheet = ss.getSheetByName("ORP_completati"); var fn = e.parameter.FN; var rg = sh.getDataRange().getValues(); const now = new Date(); // Create/Add new record, using comma separated values if ( fn == 'CREATE' ) { var data = e.parameter.DATA.split(','); sh.appendRow(data); return ContentService.createTextOutput("New record created"); } // Reads/Returns all data as a stringified JSON List else if ( fn == 'READ' ) { return ContentService.createTextOutput(JSON.stringify(rg)); } // Edit/Update existing record, requires index/row and current col1 to match else if ( fn == 'UPDATE' ) { var index = e.parameter.INDEX; //index in list var col1 = e.parameter.COL1; // current/existing value of col1 - it could be replaced... var data = e.parameter.DATA.split(','); //new data var range = sh.getRange((parseInt(index)+1),1,1,data.length); for (var i = 0; i < rg.length; i++ ) { if ( index != undefined && i == index && col1 == rg[i][0] ) { range.setValues([data]); } } return ContentService.createTextOutput("Record updated"); } // deletes a single record (and its row) from sheet. Requires row index and col1 to match else if ( fn == 'DELETE' ) { var index = e.parameter.INDEX; //index in list var col1 = e.parameter.COL1; // current/existing value of col1 - it could be replaced... for (var i = 0; i < rg.length; i++ ) { if ( index != undefined && i == index && col1 == rg[i][0] ) { sh.deleteRow(parseInt(index)+1); } } return ContentService.createTextOutput("Versione 7 mod 9"); } } I hope everything is clear and I want to thank you in advance for your help
First, get the last column with content (you will need this in order to copy all the columns in the row) var lastColumn = sh.getLastColumn() Second, get the full row. getSheetValues takes 4 values: startRow, startColumn, number of rows and number of columns. var copyRow = sh.getSheetValues(parseInt(index)+1, 1, 1, lastColumn) Third, append the row to the logSheet sheet - Keep in mind that getSheetValues returns a 2D array and the appendRow function only takes a 1D array so you have to pass the first element. logSheet.appendRow(copyRow[0]) Finally, you can delete the row sh.deleteRow(parseInt(index)+1); Resources: https://developers.google.com/apps-script/reference/spreadsheet/sheet#getSheetValues(Integer,Integer,Integer,Integer) https://developers.google.com/apps-script/reference/spreadsheet/sheet#appendrowrowcontents
Copy/paste values using google app script
Here is the sheet with an example of the data that I'm using https://docs.google.com/spreadsheets/d/1_k3xclEgdREfMMks7H2-uk0tzxXqCaoeVW_G8ase-3o/edit?usp=sharing I only put the formulas on the rows without color, and the information about the schedule comes from other tab. the colors in green are the ones with dates, where I store inside the numbers, and the blue ones also contain formulas and I wanna skip those columns when pasting the values because is correlated to another worksheet, so I can't paste the values I've tryied two ways this first one I receive an erro message: Exception: The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues. //destination = sheet.getRange(1,colA[j],table.length,1) //destination.setValues(table); // where we paste the values by column For this one, it paste on other tab on the first columns //sheet.getRange(1,colA[j],table.length,1).copyTo(sheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false); Here is the script that Im using function PasteValues() { var ss = SpreadsheetApp.openById("..."); var sheet = ss.getSheetByName("Testsheet"); var rows = sheet.getDataRange().getValues(); var dates = rows[2]; //Logger.log(dates) var yesterday = new Date(Date.now() - 864e5); var numbers = []; for(var i = 2; i < dates.length; i++) { let columns = i if (dates[i]!=="" && dates[i] !== null){ numbers.push(columns); } if (dates[i]==="") { continue; } if (dates[i].getDate() == yesterday.getDate() && dates[i].getMonth() == yesterday.getMonth() ){ break; } } colA=numbers.slice(-5) var table = []; Logger.log(rows.length) Logger.log(colA) for(var j=0;j<colA.length;j++) { table =[]; for (var i = 0; i < rows.length;i++ ) { table[i] = rows[i][colA[j]]; } Logger.log("the number of the column is: "+colA[j]); Logger.log(table); // where I paste the data } } This is the example on how my data is to copy/paste it based on the column number
When you retrieve values from the spreadsheet, getValues() already returns them to you in a 2-D array - there is no need to manually transfer them into another array You can either do: var table = sheet.getDataRange().getValues(); destination = sheet.getRange(1,statColumn,table.length,table[0].length); destination.setValues(table); Or: sheet.getDataRange.copyTo(sheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false); UPDATE Exception: The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues. means that you are trying to assign a row (1-D array) to a range (2-D array). Also, table.length will retrieve you the number of columns and not rows if table is a row. This can be easily solved by defining: table = [table]; Sample snippet: for(var j=0;j<colA.length;j++) { table =[]; for (var i = 0; i < rows.length;i++ ) { table[i] = rows[i][colA[j]]; } Logger.log("the number of the column is: "+colA[j]); table = [table]; Logger.log(table); // where I paste the data destination = sheet.getRange(1,colA[j],table.length,1) destination.setValues([table]); // where we paste the values by column } UPDATE If what you want is to copy paste selected data column by column, you need to create a 2D array table and populate it as following: for(var i = 2; i < dates.length; i++) { let columns = i if (dates[i]!=="" && dates[i] !== null){ numbers.push(columns); } if (dates[i]==="") { continue; } if (dates[i] instanceof Date && dates[i].getDate() == yesterday.getDate() && dates[i].getMonth() == yesterday.getMonth() ){ break; } } colA=numbers.slice(-5) var table = []; Logger.log(rows.length) Logger.log(colA) for(var j=0;j<colA.length;j++) { for (var i = 0; i < rows.length;i++ ) { table[i] =[]; table[i][0] = rows[i][colA[j]]; } Logger.log("the number of the column is: "+colA[j]); Logger.log(table); // where I paste the data destination = sheet.getRange(1,colA[j],table.length,1) destination.setValues(table); // where we paste the values by column } It is important to make sure that the array is 2-dimensional and that its dimensions (rows and columns) correspond to the dimensions of the range into which you want to set the data.
Google app scripts: Assign zero for empty cells
I am new to Google Apps Script, trying to set values to a column based on its current value and a flag. If Flag = Y then floor the value in C1: C1 column value =23.9895 Expected value=23 If Flag = N then round the existing value in C1: C1 column value =23.9895 Expected value=24 If the flag is either Y or N then write 0: C1 column value=empty cell Expected Value=0 I already implemented the below code. It was working partially. The first two scenarios works fine but the third scenario fails. When I try to set zero, I am getting #NUM! error instead of zero. Not sure how to do it. ... do { sRange = "Q" + iCt; if ((gDecimalInPrice == "Y") && (!isNaN(sheet.getRange(sRange).getValue()))) { sheet.getRange(sRange).setValue(Math.abs(parseInt(sheet.getRange(sRange).getValue()))); } else if ((gDecimalInPrice == "N") && (!isNaN(sheet.getRange(sRange).getValue()))) { sheet.getRange(sRange).setValue(Math.abs(Math.round(sheet.getRange(sRange).getValue()))); } else { sheet.getRange(sRange).setValue(sheet.getRange(sRange).getValue()); } iCt = iCt + 1; } while (iCt <= gRowCt);
It's much faster to do this via batch operations (and follows official best practices). These read the values into a "2D" JavaScript array (an array of arrays of values), and then you can do all your logic in memory, rather than repeatedly requesting data from the slow Spreadsheet interface. function foo() { const wb = SpreadsheetApp.getActive(); const sheet = wb.getSheetByName("the sheet name"); if (!sheet) throw new Error("Sheet with that name is missing"); const lastRow = sheet.getLastRow(); const flags = sheet.getRange("A1:A" + lastRow).getValues(); const valueRange = sheet.getRange("Q1:Q" + lastRow); const newValues = valueRange.getValues().map(function (row, i) { return row.map(function (value) { var flag = flags[i][0]; if (!flag || (value && isNaN(value))) // No "Y" or "N", or value is non-nullstring non-number, so return value as-is return value; else if (flag === "Y") return value ? Math.floor(parseFloat(value)) : 0; else if (flag === "N") return value ? Math.round(parseFloat(value)) : 0; else // Unknown flag value return value; }); }); // Write all processed values at once valueRange.setValues(newValues); } As always, you should monitor macro and triggered functions for errors by reviewing your Stackdriver logs (accessible via the Script Editor's "View" menu). Array#map
Google Apps Script: how to copy paste ranges based on formulas?
I have a model in Google Sheets that is set up with one column per day. It contains both actuals and forecasts, and every day I need to roll forward formulas to replace forecasts with actuals. I can't roll forward the whole column, only a segment of it (there are reference numbers above and below that shouldn't be changed). I have tried to write a script to do this for me every day, but I don't know how to make getRange reference a dynamic range. This is my attempt: function rollColumn() { var ss2 = SpreadsheetApp.openById('<ID redacted>'); ss2.getRange("=index(Model!$7:$7,,match(today()-2,Model!$4:$4,0)):index(Model!$168:$168,,match(today()-2,Model!$4:$4,0))").copyTo(ss2.getRange("=index(Model!$7:$7,,match(today()-1,Model!$4:$4,0)):index(Model!$168:$168,,match(today()-1,Model!$4:$4,0))")) }; The INDEX formulas work insofar as they reference the relevant ranges (I have tested them in the spreadsheet). But clearly getRange doesn't accept formulas as an input. It also seems that Google Sheets doesn't allow for a named range to be created with formulas (which is how I would solve this in Excel). Can someone help me recreate this functionality with GAS? This is the closest existing question I've found on Stack Overflow, but I haven't been able to make it work: Google Apps Script performing Index & Match function between two separate Google Sheets Thank you!
You should add {contentsOnly:false} parameter to your code. something like this: TemplateSheet.getRange("S2:T2").copyTo(DestSheet.getRange("S2:T"+LRow2+""), {contentsOnly:false});
Getting a date from column's title, then pasting formulas to the row to the right: // note: we assume that sheet is disposed as in the following document: https://docs.google.com/spreadsheets/d/1BU2rhAZGOLYgzgSAdEz4fJkxEcPRpwl_TZ1SR5F0y08/edit?ts=5a32fcc5#gid=0 function find_3formulas() { var sheet = SpreadsheetApp.getActiveSheet(), leftTitle, // this variable will stay unused because we do not need a vertical index topTitle = todayMinus_xDays(2), topTitlesRange = sheet.getRange("G3:T3"), leftTitlesRange = sheet.getRange("A4:A8"); // this range will stay unused. var coor = findCoordinates(leftTitlesRange, leftTitle, topTitlesRange, topTitle); if (coor.row == null || coor.column == null) { sheet.getRange("M12:M14").setFormula('="NULL: please check logs"'); return; } var rowAxis = 4 + coor.row; var colAxis = 8 + coor.column; var fromRange = sheet.getRange(rowAxis, colAxis, 3, 1); var toRange = sheet.getRange(rowAxis, colAxis + 1, 3, 1); Logger.log(fromRange.getA1Notation()) Logger.log(toRange.getA1Notation()); var threeFormulas = fromRange.getFormulas(); toRange.setFormulas(threeFormulas) } // unused in current script! function findCoordinates(leftTitlesRange, leftTitle, topTitlesRange, topTitle) { var formattedDate, row = 0, column = 0; if (leftTitle) { row = findRow(leftTitlesRange, leftTitle); } if (topTitle) { column = findColumn(topTitlesRange, topTitle); } var array = {row:row, column:column} return array; } // unused in current script! function findRow(range, valueToSearch) { var colRows = range.getValues(); for (i = 0; i < colRows.length; i++) { if (valueToSearch == colRows[i][0]) {return i;} } // however, if found nothing: Logger.log("the value " + valueToSearch + " could not be found in row titles"); return null; } // assumes that column titles are dates, therefore of type object. function findColumn(range, valueToSearch) { var colTitles = range.getValues(); for (i = 0; i < colTitles[0].length; i++) { if (typeof colTitles[0][i] == "object") { formattedDate = Utilities.formatDate(colTitles[0][i], "GMT", "yyyy-MM-dd") }; if (valueToSearch === formattedDate) {return i;} } // however, if found nothing: Logger.log("today's date, " + valueToSearch + ", could not be found in column titles"); return null; } // substracts 2 days from today, then returns the result in string format. function todayMinus_xDays(x) { var d = new Date(); d = new Date(d - x * 24 * 60 * 60 * 1000); d = Utilities.formatDate(d, "GMT", "yyyy-MM-dd"); return d; }
Spreadsheets to calendar depending on the decision of an operator
Hello I am making a script that takes data from a worksheet (which receives data from a form) creates an event in my main calendar depending on the decision of an operator. It receives the data from the form in columns A through F. In column G the operator decides whether to "Yes" or "No". If G is "Yes" the script checks in column H if something is written. If it is empty The script writes to column H and creates an event with the data of A: F, If not something is written in column H it simply passes to the next line until the last one is written. My script works correctly only if the entire H column is empty. This forces me to always clear column H and duplicate events already written to the calendar with each new entry. How do I get the script to continue running without having to clear the H column? My script is: function teste() { var ss = SpreadsheetApp.getActive(); var dados = ss.getDataRange().getValues(); var ultimaLinha = ss.getLastRow() - 1; var options = { description: dados[ultimaLinha][2], location: dados[ultimaLinha][5], }; for (var i = 1; i < ultimaLinha + 1; i++) { var validacao = dados[i][6]; var escrita = dados[i][7]; if (validacao === "Yes") { if (escrita == null) { SpreadsheetApp.getActiveSheet().getRange(i + 1, 8).setValue('ok'); var event = CalendarApp.getDefaultCalendar().createEvent( dados[i][1], new Date(dados[i][3]), new Date(dados[i][4]), options); } } } My worksheet
When you getValues() the empty cells in the data array still exist, they just contain an empty string. Change null to "" if (escrita == "") { ... }
If I understand your summary correctly, I think you need to remove the following check. if (escrita == null) {