Automate historic data collection from CoinGecko with Google Sheets - google-sheets

Been collecting historical bitcoin data from CoinGecko API using Google Sheets. Manual method where I have to open the sheet and copy and "Paste values only" to paste data in the history list. History on the left side and data collection on the right.
I want to automate this process if possible. Current code pulls 10 rows of data that's not in the history yet. The history row ends in a "BOTTOM" field to indicate bottom of page. Script Editor already set to run at midnight for data collection.
Here is my example:
https://docs.google.com/spreadsheets/d/1kAcVtF2x9ox7gNCt5liQdhApQpGaBw1kl4I8PjKMfx8/edit?usp=sharing

Answer
You have to make use of the Sheet and Range classes.
Code
In order to automate that process add the following code to your existing Apps script:
function Pull_History_bitcoin() {
//PREVIOUS CODE
var days = parseInt(targetSheet.getRange("J4").getValue().toString());
if (days > 0) {
var range = targetSheet.getRange("G6:J" + (5+days)).getValues();
var lastRowHistory = targetSheet.getRange("G1").getValue();
var nextLastRowHistory = parseInt(lastRowHistory[1]) + days;
var bottomCell = targetSheet.getRange("A" + nextLastRowHistory);
bottomCell.setValue("BOTTOM");
var nextRange = targetSheet.getRange(`${lastRowHistory}:D` + (nextLastRowHistory - 1));
nextRange.setValues(range);
}
}
Where days define the number of entries after calling the external API.
Don't worry about the values rounded because they are just showing rounded, the current values are like the original ones.
Reference
Sheet class
Range Class

Here below find my full google-apps-script as reference to anyone wishing to acquire crypto historical information from the free CoinGecko Api service.
function Pull_History_bitcoin() {
var targetSS = SpreadsheetApp.getActive();
var targetSheet = targetSS.getSheetByName("bitcoin");
// To force an update
targetSheet.insertRowBefore(3);
targetSheet.deleteRow(3);
// Copy newly acquired history into the history columns
var days = parseInt(targetSheet.getRange("J4").getValue().toString());
if (days > 0) {
var range = targetSheet.getRange("G6:J" + (5+days)).getValues();
var lastRowHistory = targetSheet.getRange("G1").getValue();
//var nextLastRowHistory = parseInt(lastRowHistory[1],4) + days;
var nextLastRowHistoryStr = lastRowHistory.slice(1);
var nextLastRowHistory = Number(nextLastRowHistoryStr) + days;
var nextRange = targetSheet.getRange(`${lastRowHistory}:D` + (nextLastRowHistory - 1));
nextRange.setValues(range);
var bottomCell = targetSheet.getRange("A" + nextLastRowHistory);
bottomCell.setValue("BOTTOM");
}
}

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.

Is it possible to get the high and low of a stock price during the day over a specific timeframe?

Like the title says, is there a way to get the highs and lows of a stock price during the day after a certain time? There's a way to get the days high and low over a period of time:
=GOOGLEFINANCE("AMZN","high","05/01/2020","05/10/2020","DAILY")
=GOOGLEFINANCE("AMZN","low","05/01/2020","05/10/2020","DAILY")
But what about during the day during a specific time period? For example from 9:12AM PST to 11:23AM PST?
Solution#3 : you can use Alpha Vantage by 2 ways, add-on GSheets or a custom function i.e. :
// mike steelson
var apikey = 'xxxxxxxxxxxxxx'
function getAllDataJSONv2(code) {
var url = 'https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol='+code+'&interval=5min&apikey='+apikey
var data = JSON.parse(UrlFetchApp.fetch(url).getContentText())['Time Series (5min)']
var resultat = []
for (var elem in eval(data)){
resultat.push([elem,eval(data[elem]['1. open']),eval(data[elem]['2. high']),eval(data[elem]['3. low']),eval(data[elem]['4. close']),eval(data[elem]['5. volume'])])
}
return resultat
}
the apikey is free for up to 500 requests a day. https://rapidapi.com/alphavantage/api/alpha-vantage
no, not possible with GOOGLEFINANCE. you can get only the daily value which is usually from 16:00:00
your only other option is to find some website (which doesn't use JavaScript) that holds values you wish for and scrape it into google sheets
Solution1 : You can use Yahoo Finance to retrieve the information you want
function getHistoric(url){
var source = UrlFetchApp.fetch(url).getContentText()
var jsonString = source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}'
var data = JSON.parse(jsonString).context.dispatcher.stores.HistoricalPriceStore.prices
var result = []
data.forEach(function(elem){
result.push([elem.date,elem.open,elem.high,elem.low,elem.close])
})
return result
}
https://docs.google.com/spreadsheets/d/1Kly5-Vu5jBfrl6xFljdICFJW369X-OCjB22z3Ouzt4Y/copy
Solution#2 : you can build your own data based on yahoo finance https://docs.google.com/spreadsheets/d/1QlqpPkIMjE8_jT6kNME1cLrMmQZ9cSzG-SR2Jjivvqo/edit?usp=sharing
//Mike Steelson
var histo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('historic')
var code = histo.getRange('B1').getValue()
//put a trigger on historic
function historic(){
if (testDateHour()==true) {histo.appendRow([new Date(),marketPrice(code)])}
}
function marketPrice(code) {
var source = UrlFetchApp.fetch('https://finance.yahoo.com/quote/'+code).getContentText()
var data = JSON.parse(source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}')
return data.context.dispatcher.stores.StreamDataStore.quoteData[code].regularMarketPrice.raw
}
function testDateHour(){
var d = new Date();
// not on sunday and saturday and between 10am and 4pm
if (d.getDay()!=0 && d.getDay()!=6 && d.getHours()>=10 && d.getHours()<=16) {return true}else{return false}
}
Configure your local settings (PST) + update if necessary the period when you want to retrieve the information. Then put the trigger (1min)

Delete Rows older than 1 year in Google Sheets (Large Data Set)

I have a fairly large dataset containing about 40,000 rows (New rows added daily). I want to run a script daily that deletes rows that are older than 1 year.
I have been using this one that has worked ok, but as my dataset gets larger it times out and fails to run.
here is what I have been using:
function deleteFIVEoh() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("theFIVEoh");
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();//today
var yearOld = Date.now() + -365*24*3600*1000;
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][4];// arrays are 0 indexed so row1 = values[0] and col12 =.
[11]
if ((tempDate!="") && (tempDate <= (yearOld)))
{
sheet.deleteRow(i);
}
}
}
The data on my sheet is always sorted in ascending order (oldest entries at the top). Is there any way I can get this to work faster? Maybe by looking at the first 500 rows only?
Thanks in advance!
-wes
Since your sheet is sorted in ascending order, it is much better to start at the top, count the number of rows that satisfy your condition, then use a single deleteRows() method.
function deleteFIVEoh() {
const MS_IN_ONE_YEAR = 365*24*3600*1000;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("theFIVEoh");
var datarange = sheet.getDataRange();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();//today
var yearOld = new Date(currentDate.getTime() - MS_IN_ONE_YEAR);
for (i = 0; values[i][4] < yearOld; i++) {}
sheet.deleteRows(1,i);
}
A single call is much faster than a looped API call, and there are less iterations in this code as well as it does not need to go through the entire sheet.
Sample before execution:
Sample after execution:

Modify script to copy data validation from a list and timestamp on edit of that data validation to new rows each time an edit is made

I created a sign out for study halls where students select from a dropdown on the master page to find their destination which also creates a timestamp and copies the row to another tab which each homeroom teacher can monitor to see who should be in their room and when they left the previous room. This way teachers can look at their individual pages to see who should be in their rooms at any time, they will know who is supposed to be coming to their rooms, and they have access to where their kids are going to on the master sheet if needed.
Some teachers have asked about using this system throughout the day as they have wandering students or students that try to leave every period. Right now, the script I am running will update the drop-down column and timestamp on each edit, but I would also like to copy the edited dropdown and timestamp information to new columns on the master each time a student checks out of one room to go to another. This way teachers could see on the master list where and when students are going across classes which could help identify issues that might need to be addressed. I created new columns called Destination 1 and Time 1, Destination 2, and Time 2, etc. but I am not sure how to get the information to those columns. Each time a student leaves, I would want the information to be put into the first available column next to their name.
FYI, I have only modified a few scripts previously, and do not write my own scripts.
Link to a copy of the Google Doc I setup. The Master tab has a copy of all the students and each of the other tabs pulls information from the master based on what is selected in row F.
https://docs.google.com/spreadsheets/d/1JDdiKGGIaOVBUSIVxOTK56uceerR1iNuoD7wKowqAfU/edit?usp=sharing
function onEdit(event)
{
var timezone = "EST";
var timestamp_format = "HH:mm:ss"; // Timestamp Format.
var updateColName = "Student Destination";
var timeStampColName = "Time";
var sheet = event.source.getSheetByName('Master'); //Name of the
sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1,
sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(timeStampColName);
var updateCol = headers[0].indexOf(updateColName); updateCol =
updateCol+1;
if (dateCol > -1 && index > 1 && editColumn == updateCol) { //
only timestamp if 'Last Updated' header exists, but not in the
header row itself!
var cell = sheet.getRange(index, dateCol + 1);
var date = Utilities.formatDate(new Date(), timezone,
timestamp_format);
cell.setValue(date);
}
}
When I choose a destination in row F, the timestamp is generated and the others tabs are updated. I just need to copy each of the edit results to new columns which I have named Destination 1 and Time 1, Destination 2, and Time 2, etc.
The OP code is good but doesn't make use of onEdit. The event parameter of the onEdit function/trigger provides data concerning the edit. Details are described in the documentation.
In the scenario that the OP has outlined, the first issue is to evaluate whether there is already a time in Column G.
EXISTING TIME?
If there is an existing time, then any existing data in Destination 1 to 5 must be copied to destinations 2 to 6, then the existing student name and time must be copied to Destination 1, and then, and only then, can the new date can be applied.
1- Existing data in Destination 1 to 5 must be copied to destinations 2 to 6
var rangeToCopy = sheet.getRange(actRngRow, 9, 1, 10);
rangeToCopy.copyTo(sheet.getRange(actRngRow, 11));
This leaves room to copy/paste the existing student name and time to destination 1.
2- Copy the existing student name and time to Destination 1
var oldDate = sheet.getRange(actRngRow, actRngCol + 1);`
This is simply the column beside the edited cell.
// copy the old student name and date to destination 1
var oldStudentName = event.oldValue;
var oldDateValue = oldDate.getValue();
var Dest1StudentName = actRng.offset(0, 3).setValue(oldStudentName);
var Dest1DateValue = actRng.offset(0, 4).setValue(oldDateValue);
offset enables the code to use a relative reference. In this case, the column reference is the number of columns to the right of the edited cell. The name of the student is made available by event.oldValue, and the time is the value in Column G (because we haven't yet updated that column).
INSERT UPDATED TIME IN COLUMN G
The existing code works well
// add the date to the adjacent cell
var cell = sheet.getRange(actRngRow, actRngCol + 1);
var newdate = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(newdate);
The complete code is:
function onEdit(event) {
Logger.log("start onedit");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Master")
//so_53888444
var timezone = "EST";
var timestamp_format = "HH:mm:ss"; // Timestamp Format.
var updateColName = "Student Destination";
var timeStampColName = "Time";
//var debug_e = {
// authMode: event.authMode,
// range: event.range.getA1Notation(),
// source: event.source.getId(),
// user: event.user,
// value: event.value,
// oldValue: event. oldValue
//};
//Logger.log("AuthMode: "+debug_event.authMode);// DEBUG
//Logger.log("Range: "+debug_event.range);// DEBUG
//Logger.log("Source: "+debug_event.source);// DEBUG
//Logger.log("User: "+debug_event.user);// DEBUG
//Logger.log("user email"+debug_event.user.getEmail());// DEBUG
//Logger.log("Value: "+debug_event.value);// DEBUG
//Logger.log("Old value: "+debug_event.oldValue);// DEBUG
//Logger.log("AuthMode: "+debug_event.authMode+", Range: "+debug_event.range+", source: "+debug_event.source+", user: "+debug_event.user+", value: "+debug_event.value+", old value: "+debug_event.oldValue);// DEBUG
//Logger.log("the old value: "+event.oldValue);
var actRng = event.range;
//Logger.log("the edited range was " + actRng.getA1Notation()); //DEBUG
var actRngRow = actRng.getRow();
var actRngCol = actRng.getColumn();
var oldDate = sheet.getRange(actRngRow, actRngCol + 1);
var status = 0;
if (actRngRow > 1 && actRngCol == 6) { // only timestamp if 'Last Updated' header exists, but not in the header row
if (oldDate.isBlank()) {
//Logger.log("the date is blank - no historic data to copy");
} else {
//Logger.log("the date NOT blank - copy the historic data");
// copy/paste existing destinations
var rangeToCopy = sheet.getRange(actRngRow, 9, 1, 10);
rangeToCopy.copyTo(sheet.getRange(actRngRow, 11));
// copy the old student name and date to destination 1
var oldStudentName = event.oldValue;
var oldDateValue = oldDate.getValue();
var Dest1StudentName = actRng.offset(0, 3).setValue(oldStudentName);
var Dest1DateValue = actRng.offset(0, 4).setValue(oldDateValue);
}
// add the date to the adjacent cell
var cell = sheet.getRange(actRngRow, actRngCol + 1);
var newdate = Utilities.formatDate(new Date(), timezone, timestamp_format);
cell.setValue(newdate);
}
}

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.
:)

Resources