How to create an "Open in Google Sheets" button - google-sheets
I already have an "export to CSV" button on my site. But I'd like to have an "Open in Google Sheets" button, which opens the CSV directly into Google Sheets.
That'll save the user a few steps, so they will no longer have to (1) download the CSV, and (2) import it into Google Sheets.
Any way to do this?
If you wanted to avoid the full API . . .
Use Google Script to import the CSV into a Google Sheet and set the script trigger to run on a sensible schedule (every, minute, hour, day etc.).
//adapted from http://stackoverflow.com/a/26858202/3390935
function importData() {
var ss = SpreadsheetApp.getActive();
var url = 'HTTP://YOURURL.COM/FILE.CSV';
var file = UrlFetchApp.fetch(url); // get feed
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv); // see below for CSVToArray function
var sheet = ss.getActiveSheet();
// loop through csv data array and insert (append) as rows into 'NEWDATA' sheet
for ( var i=0, lenCsv=csvData.length; i<lenCsv; i++ ) {
sheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
};
// http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.
function CSVToArray( strData, strDelimiter ) {
// Check to see if the delimiter is defined. If not,
// then default to COMMA.
strDelimiter = (strDelimiter || ",");
// Create a regular expression to parse the CSV values.
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [[]];
// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;
// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec( strData )){
// Get the delimiter that was found.
var strMatchedDelimiter = arrMatches[ 1 ];
// Check to see if the given delimiter has a length
// (is not the start of string) and if it matches
// field delimiter. If id does not, then we know
// that this delimiter is a row delimiter.
if (
strMatchedDelimiter.length &&
(strMatchedDelimiter != strDelimiter)
){
// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );
}
// Now that we have our delimiter out of the way,
// let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]){
// We found a quoted value. When we capture
// this value, unescape any double quotes.
var strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
var strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
// Return the parsed data.
return( arrData );
};
Make that sheet public and append /copy to the URL.
https://docs.google.com/spreadsheets/d/YOURGDOCID/copy
You can use the Google Sheets API.
This link provides guides for several programming languages, references, samples, etc. https://developers.google.com/sheets/
Good luck.
Related
Getting text from range in google sheets to a google doc NOT in a table
I have read everything I could find on this site and others about methods of getting text out of a google sheet and into a google doc. I don't want the "data" in a table. It's not a huge amount of data to work with, so I'm able to tinker with the source sheet a bit and found a solution using a ListItem append approach. Here's what I've come up with: function onOpen() { const ui = SpreadsheetApp.getUi(); ui.createMenu('Agenda') .addItem('CreateAgenda', 'createagenda') .addToUi(); } function createagenda() { // take info from agenda topic google spreadsheet and put in a google doc var documentId=DriveApp.getFileById('_______________').makeCopy().getId(); //add today's date to new filename var d = new Date(); var curr_date = d.getDate(); var curr_month = d.getMonth() + 1; var curr_year = d.getFullYear(); var theDate = curr_month + "_" + curr_date + "_" + curr_year; DriveApp.getFileById(documentId).setName(theDate + '_CommitteeAgenda'); const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("AgendaPlanning"); //Determine how many items are in the list to set count in For Loop sheet.getRange('B2').activate(); // Starting cell in column with agenda items sheet.getCurrentCell().getNextDataCell(SpreadsheetApp.Direction.DOWN).activate(); var last_row_submissions = sheet.getCurrentCell().getRowIndex(); const body = DocumentApp.openById(documentId).getBody(); for (var i=2; i<= last_row_submissions; i++){ var currentline = sheet.getRange(i,14).getValue(); var agenda_item = body.appendListItem(currentline); } var documentsInPacket = sheet.getRange("B28").getValue(); var doclist = body.appendListItem(documentsInPacket); } For the most part this works because items on the agenda document are numbered, but because I've used the ListItem approach, the final item (Documents) has a number to it (18) which I don't want. Since someone has to go in and put in meeting info (zoom link, etc.) then having one more thing to do isn't horrible, but.... Minutes (6:30) Commentary (6:35) Adjourn (6:40) Documents: Superintendent report; .....etc. ? Is there an easier way to do this? Can I get rid of the number preceding the last item? How can you get the value of a cell from sheets and have google doc accept it as text? Thank you!
You can use body.appendParagraph(documentsInPacket) instead of body.appendListItem(documentsInPacket) to achieve the results you are looking for.
Using GSheets Script to increment value of duplicate by 1
I want to check a row for duplicates and if match increment these by 1. The data I want to manipulate this way is LAT LONG Coordinates. They originate from an aggregated data acquisition, where users can only insert country and city. Via an Add-On these will get GEO coded. Problem is, that I need to slightly change the values of duplicate entries, in order to display them on a map. Easiest way (I think) is to increment a LAT or LONG coordinate by 1 if there is already an entry with the same value. Data sample & results of script Any idea how to do this via Script? My code, originally intended to delete duplicate rows: function overwriteDuplicates() { var ss=SpreadsheetApp.getActive(); var sh=ss.getSheetByName("Formularantworten 2"); var vA=sh.getDataRange().getValues(); var hA=vA[0]; var hObj={}; hA.forEach(function(e,i){hObj[e]=i;});//header title to index var uA=[]; var d=0; for(var i=0;i<vA.length;i++) { if(uA.indexOf(vA[i][hObj['Latitude']])==-1) { uA.push(vA[i][hObj['Latitude']]); }else{ function increment() { SpreadsheetApp.getActiveSheet().getRange('K').setValue(SpreadsheetApp.getActiveSheet().getRange('K').getValue() + 1); } }}}
You want to modify the latitude whenever duplicate coordinates (latitude and longitude is found). In this case, you can do the following: Get all the values in the sheet, and retrieve the indexes where Latitude and Longitude are, based on the headers. Loop through all rows (excluding headers), and for each row, check whether a previous row contains these coordinates. If that's the case (isDuplicate), increment the last number in the latitude (after the last .), or decrement it if it's close to 999 (I assume there's always 3 digits). Store the new latitude in an array after modification. Use setValues to write the modified latitudes to the sheet. Below is a possible code snippet to do this (see inline comments for details). Code snippet: function overwriteDuplicates() { const ss = SpreadsheetApp.getActive(); const sheet = ss.getSheetByName("Formularantworten 2"); const values = sheet.getDataRange().getValues(); const headers = values.shift(); // Retrieve first row (headers) const latColumn = headers.indexOf("Latitude"); // Latitude column index const longColumn = headers.indexOf("Longitude"); // Longitude column index let outputLocations = []; for (let i = 0; i < values.length; i++) { // Loop through rows const newLocation = { // Store object with current location "latitude": values[i][latColumn], "longitude": values[i][longColumn] } let isDuplicate; do { // Check if location is duplicate, and increment if necessary isDuplicate = outputLocations.some(location => { const sameLatitude = location["latitude"] === newLocation["latitude"]; const sameLongitude = location["longitude"] === newLocation["longitude"]; return sameLatitude && sameLongitude; }); if (isDuplicate) newLocation["latitude"] = modifyCoord(newLocation["latitude"]); } while (isDuplicate); outputLocations.push(newLocation); // Store new location in array } let outputLatitudes = outputLocations.map(location => [location["latitude"]]); // Retrieve latitudes from array sheet.getRange(2, latColumn+1, sheet.getLastRow()-1).setValues(outputLatitudes); // Write updated latitudes to sheet } function modifyCoord(coordinates) { let coordArray = coordinates.split("."); let lastCoord = coordArray.pop(); if (lastCoord > 990) lastCoord--; else lastCoord++; coordArray.push(lastCoord); return coordArray.join("."); } Output:
Search entire column for string, return all row values
Trying to to write a script to search through column A starting at the top, and return all values of the row on which it matches a string. I want to have it output the values in plain html, while the string would be defined from a parameter on the url line. function doGet(e) { var param = e.parameter.param; var sheet = SpreadsheetApp.openById("SHEETID").getSheetByName("Sheet1"); var column = sheet.getRange("A"); var values = column.getValues(); var row = 0; while ( values[row] && values[row][0] !== param ) { row++; } if (values[row][0] === param) var output = row.getValues() return ContentService.createTextOutput(output); } Other errors as well while changing code... Range not found (line 5, file "Code", project "Column Search")
Unfortunately You cannot retrieve a range as getRange("A") You cannot modify your code to var column = sheet.getRange("A:A"); However keep in mind that this will make your code very slow. Consider retrieving only the range that actually has contents: var lastRow=sheet.getLastRow(); var column = sheet.getRange(1,1,lastRow,1); References: getRange(row, column, numRows, numColumns) getLastRow()
Google docs to google sheets script
I’m using Google Sheets to conduct some text analysis. I would like to automate the process by linking a spreadsheet to a Google doc file on my GDrive to extract text directly. It doesn’t have to structured/formatted. It just has to be a plain text. Does it take a comprehensive scripting or the task of copying text is simple? I searched the web but couldn’t find one.
To help you start, here is an SO thread. Same scenario: Get data from the Google Sheets and copy it to the Google Docs. A reference from Open Source Hacker: Script for generating Google documents from Google spreadsheet data source. Here is the code provided in the article. You can modify it by yourself depending on your use. /** * Generate Google Docs based on a template document and data incoming from a Google Spreadsheet * * License: MIT * * Copyright 2013 Mikko Ohtamaa, http://opensourcehacker.com */ // Row number from where to fill in the data (starts as 1 = first row) var CUSTOMER_ID = 1; // Google Doc id from the document template // (Get ids from the URL) var SOURCE_TEMPLATE = "xxx"; // In which spreadsheet we have all the customer data var CUSTOMER_SPREADSHEET = "yyy"; // In which Google Drive we toss the target documents var TARGET_FOLDER = "zzz"; /** * Return spreadsheet row content as JS array. * * Note: We assume the row ends when we encounter * the first empty cell. This might not be * sometimes the desired behavior. * * Rows start at 1, not zero based!!! 🙁 * */ function getRowAsArray(sheet, row) { var dataRange = sheet.getRange(row, 1, 1, 99); var data = dataRange.getValues(); var columns = []; for (i in data) { var row = data[i]; Logger.log("Got row", row); for(var l=0; l<99; l++) { var col = row[l]; // First empty column interrupts if(!col) { break; } columns.push(col); } } return columns; } /** * Duplicates a Google Apps doc * * #return a new document with a given name from the orignal */ function createDuplicateDocument(sourceId, name) { var source = DocsList.getFileById(sourceId); var newFile = source.makeCopy(name); var targetFolder = DocsList.getFolderById(TARGET_FOLDER); newFile.addToFolder(targetFolder); return DocumentApp.openById(newFile.getId()); } /** * Search a paragraph in the document and replaces it with the generated text */ function replaceParagraph(doc, keyword, newText) { var ps = doc.getParagraphs(); for(var i=0; i<ps.length; i++) { var p = ps[i]; var text = p.getText(); if(text.indexOf(keyword) >= 0) { p.setText(newText); p.setBold(false); } } } /** * Script entry point */ function generateCustomerContract() { var data = SpreadsheetApp.openById(CUSTOMER_SPREADSHEET); // XXX: Cannot be accessed when run in the script editor? // WHYYYYYYYYY? Asking one number, too complex? //var CUSTOMER_ID = Browser.inputBox("Enter customer number in the spreadsheet", Browser.Buttons.OK_CANCEL); if(!CUSTOMER_ID) { return; } // Fetch variable names // they are column names in the spreadsheet var sheet = data.getSheets()[0]; var columns = getRowAsArray(sheet, 1); Logger.log("Processing columns:" + columns); var customerData = getRowAsArray(sheet, CUSTOMER_ID); Logger.log("Processing data:" + customerData); // Assume first column holds the name of the customer var customerName = customerData[0]; var target = createDuplicateDocument(SOURCE_TEMPLATE, customerName + " agreement"); Logger.log("Created new document:" + target.getId()); for(var i=0; i<columns.length; i++) { var key = columns[i] + ":"; // We don't replace the whole text, but leave the template text as a label var text = customerData[i] || ""; // No Javascript undefined var value = key + " " + text; replaceParagraph(target, key, value); } }
Google Sheets Lookup Tool Assistance
I've taken it upon myself the learn how to "excel". That made a little more sense in my head, but hey. I have built a "lookup tool" which can be viewed here. The "Dishwasher search" is working as intended. You can search by noise level or decor panel height to create a list of suitable models then pull the data into an individual search by product code/model no. I decided to make it a little more difficult and created one for Ovens. The Layout is like this; Main search>Single Oven Database>Double Oven Database>Built-under oven database. My goal is to achieve the same search facilities as the "Dishwasher tool", however I have been unsure how to search (Vlookup) from different sources. I have tried creating a "Master DB" using the formula below; ={Importrange("1mY13e-75dBYfKgkjV8dFFFEvxC838nGNxPrUdusc0PA", "'Single Ovens'!$A:$F");Importrange("1mY13e-75dBYfKgkjV8dFFFEvxC838nGNxPrUdusc0PA", "'Double Ovens'!$A:$F");Importrange("1mY13e-75dBYfKgkjV8dFFFEvxC838nGNxPrUdusc0PA", "'Built-Under Ovens'!$A:$F")))} However, it only seems to pull data from the first range not the others unless I do it horizontaly rather than vertical, but horizontal wont work with my Vlookup formula (To my knowledge). The other method I have tried is using this code; =IF(AND($A$19="Single Oven",$A$4>0), Vlookup($A$4,'Single Ovens'!$B:$F,1,False),IF(AND($A$10="Double Oven",$A$4>0), Vlookup($A$4,'Double Ovens'!$B:$F,1,False),If(AND($A$10="Built-Under Oven",$A$4>0), Vlookup($A$4,'Built-Under Ovens'!$B:$F,1,False),IF($A$10="Single Oven",Vlookup($A$7,'Single Ovens'!$A:$F,2,False),IF($A$10="Double Oven", Vlookup($A$7,'Double Oven'!$A:$F,2,False),If($A$10="Built-Under Oven", Vlookup($A$7,'Built-Under Oven'!$A:$F,2,False))))))) The above code was inserted and was "meant" to Vlookup all 3 sheets and pull "product Code" through to populate Cell D4 on sheet 'Ovens'. Now, I'm a bit of a novice at this but I'm working to understand it all :) Any suggestions you guys can make or point me in the right direction? Edit - Sorry guys. It was rude not to post my solution. I have changed my Importrange function to =Importrange("XYZ",""'Single Ovens'!$A2:$F200") and repeated this 3 times with a gap of 200 "rows" between each one. Not a solution, but a viable alternative. My friend is currently working on a script for me to achieve this. The Vlookup formula no longer needs to be as complex thanks to the importrange formula simplifying matters.
So after discussing the problem with McSheehy, and the problem is actually this. How to get data from ONE spreadsheet, multiple sheets of my choice. and write To MANY spreadsheets, Multiple sheets within those spreadsheets, of my choice. Once that data is in the right place, the current formulas should work or can be adapted easily. I came up with a script solution, The user creates a settings sheet in the source sheet. In A2 downwards, Target spreadsheet keys, B2 downwards, Source sheet names you wish to include from current sheet. C2 downwards is the target SHEET names, if you wanted to write data to more than one sheet. Bits of code are annotated to help explain McSheehy's questions on how it works. If anyone has any improvements to suggest, and I'm sure there are some, particular the headers bit. (its not needed, but my clearContent/clearConents line kept flipping out), I'm all ears. Thanks function getOvenDataV5(){ var settingsSheetName = "monkey_settings"; /* DO NOT EDIT BELOW THIS LINE */ var ss = SpreadsheetApp.getActiveSpreadsheet(); var settings = ss.getSheetByName(settingsSheetName); // this bit has been edited, note the getValues, not getValue, as we want the whole column now not just a single cell. var targetSheetsValues = settings.getRange("C2:C").getValues(); // this gets the target sheet names from the settings sheet var targetSheets = []; // And array added to throw target sheet names into, as there is more than one. // the reason we use arrays and loops (later on), is because the script has no idea how much data to expect. // so we go through whatever it's grabbed, the stuff it thinks is data, but we check it later on. // only a simple check. Our check is that it cannot be blank. "" // then stuff it in an array, a handy thing to store data, for use later on. var sSheets = settings.getRange("B2:B").getValues(); var sourceSheets = []; // new loop below to get the target sheets names. We'll use this in the write bit later. for(var i = 0; i < targetSheetsValues.length;i++){ if(targetSheetsValues[i][0]!=""){ targetSheets.push(targetSheetsValues[i]); } } for(var i = 0; i < sSheets.length;i++){ if(sSheets[i][0]!=""){ sourceSheets.push(sSheets[i]); } } var dKeys = settings.getRange("A2:A").getValues(); var sKeys = []; for(var i = 0; i < dKeys.length;i++){ if(dKeys[i][0]!=""){ sKeys.push(dKeys[i]); } } var data = []; for (var i = 0; i < sourceSheets.length;i++){ var values = ss.getSheetByName(sourceSheets[i]).getDataRange().getValues(); for (var x = 1;x < values.length; x++){ if(values[x][0]!= ""){ data.push(values[x]); } } } // Below is an array of your column headers, the script was being annoying when clearing sheet data, so decided to clear the whole damn sheet // then write the headers via here instead var headers = [["Model No", "Product Code", "Brand", "Model No", "kW", "Amp"]]; for (var i = 0; i< sKeys.length;i++){ var tss = SpreadsheetApp.openById(sKeys[i]); for(var x = 0; x < targetSheets.length;x++){ // this loop, within the keys loop, goes through the target sheets array var target = tss.getSheetByName(targetSheets[x]); // this loads the target sheet, one by one var range = target.getRange(2,1, data.length, data[0].length); // this gets the cells to write to target.clearContents(); // clear the sheet before writing data target.getRange("A1:F1").setValues(headers); // write the headers to a1:F1 in target sheet range.setValues(data); //write the data } } }
I dont know if they will be of any value but here are two things that i wrote in script. The follow is a vlookup script to set or return to memory with hints of query ish abilites. //~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~` //--//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: 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_("cat","Sheet1!A:G",4,[0],"Database!A1","y","y"); -Loads all Locations numbers from J2:J into a variable --looks for Location Numbers in Column 0 of Referance sheet and range eg "Data!A:G" ---Returns results to Column 3 of Target Sheet and range eg "test!A1" or "1,1" */ 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 } } } //~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~` //~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~` //--//Dependent on isEmpty_() //Find Last Row on Database function getFirstEmptyRowUsingArray_(sheetname) { var data = SpreadsheetApp.getActive().getSheetByName(sheetname).getDataRange().getValues(); for(var n = data.length ; n>0 ; n--) { if(isEmpty_(data[n])==false) { n++; break; } } n++; return (n); } //~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~` The Following is a ImportRange script because I hate how =importrange() requires you to "request access" on every new formula. If that importrange is embedded you have to take it out and request access and re-embed it. Also a lot of times the formula just breaks. so: //~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~` //Script Based ImportRange //Example importRange_('0AodPsggrbsh1dDNH............','Main4NS','A:G','Common','C7','y') //Explanation importRange_('Importing Spreadsheet Key or URL','Importing Spreadsheet Tab Name','Importing Spreadsheet Tab's Range','Destination Spreadsheet Tab Name','Destination Spreadsheet Tab's placement','Will add note to the first cell of import') function importRange_(Source_Key,Source_Sheet,Source_Range,Set_Sheet,Set_Pos,Add_Note) { var SourceTypeCheck = Source_Key.indexOf("https://"); if(SourceTypeCheck >= 0) { var Load = SpreadsheetApp.openByUrl(Source_Key).getSheetByName(Source_Sheet).getRange(Source_Range).getValues(); var Name = SpreadsheetApp.openByUrl(Source_Key).getName(); } if(SourceTypeCheck == -1) { var Load = SpreadsheetApp.openById(Source_Key).getSheetByName(Source_Sheet).getRange(Source_Range).getValues(); var Name = SpreadsheetApp.openById(Source_Key).getName(); } var RowVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Pos).getRow(); var ColVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Pos).getColumn(); if(Add_Note.toUpperCase() == 'Y') { SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,1,1).setNote("Import Script Updated On: " + Utilities.formatDate(new Date(), "PST", "MM-dd-yyyy hh:mm a")+"\nSS Name: "+Name+"\nRange: "+Source_Sheet+"!"+Source_Range+"\nSS Key: "+ Source_Key); } SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,Load.length,Load[0].length).setValues(Load); SpreadsheetApp.flush(); SpreadsheetApp.getActiveSpreadsheet().toast('At: '+Set_Sheet+'!'+Set_Pos,'Import Completed:'); } //~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~` Same thing stands. If you have and ideas for improvement let me know. If you find a way to integrate it, cool beans, Post some code of how you used it. :)