Google Apps Script: Get specific data and preview elsewhere - google-apps-script

I have a sheet of a long (sorted) list, with column A with date and column B with time and then some data on columns c,d,e,f.
I want to have a script function that compares current date-time to the date and time from columns A & B and then copies to columns i,j,k,l,m,n on rows 1-4 the "upcoming" data.
So I'm thinking of something like this, but unsure how to finish it. Any ideas?
function myFunction()
{
var d = new Date();
var now = d.getTime();
var as = SpreadsheetApp.getActiveSheet();
var data = as.getDataRange().getValues(); //this seems to be wrong, because I don't need all DataRange, only first 6 columns, but as many rows as those having data
var c = 0;
for(i in data)
{
var row = data[i];
//var rowdate = ??;
if (now < rowdate)
{
c++;
//copy from row to destination location
}
if (c > 4) break;
}
}

Related

How to choose a destination spreadsheet of copied data based on spreadsheet name

So I have two tables. Table 1 is a large table with 7 columns. In this table, C2:C has unique ID numbers of people. Table 2 is a smaller table with the names of all people in K3:K and the unique ID on J3:J. Table 2 only has 2 columns, the IDs and the Name. So, All IDs in C2:C exists in K3:K. All the names in K3:K are also the names of sheets in the same worksheet. So what I'm trying to do is:
Loop through the IDs in table 1 (large table) with the IDs in table 2 (small table). If the IDs are the same, then I will copy the whole row in table 1 into my destination sheet. To choose my destination sheet, I check the cell adjacent to the identified ID in table 2 and choose the sheet whose name is the same.
I hope i explained that decently. My problem it's copying things in every 10 intervals. So it copies the 10th row, then the 20th, then the 30th... and I'm confused how to even approach figuring out where I went wrong because I don't understand why it's in 10 interverals and why it's choosing the sheets that its choosing.
If it helps, link to the sheet is: https://docs.google.com/spreadsheets/d/1522hM3mO9AdaTpiS2oI1IK3wwwFXbOz1qHxcMrRzASY/edit?usp=sharing
function copystuff() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var key = SpreadsheetApp.getActiveSheet().getName();
var currentS = ss.getSheetByName(key);
var sheetNameArray = [];
sheetNameArray = sheets.map(function(sheet){ // puts sheet names into an array
return [sheet.getName()];
});
var name_master = currentS.getRange("K3:K").getValues().flat().filter(r=>r!=''); //key name
var enno_master = currentS.getRange("J3:J").getValues().flat().filter(r=>r!=''); //key ID
var enno_all = currentS.getRange("C2:C").getValues().flat().filter(r=>r!=''); // number of big table
for (x = 0; x< enno_master.length; x++){ //to loop through the key number
for (y = 0; y < enno_all.length; y++){ // to loop through the numbers of big table
if(enno_master[x]==enno_all[y]){ // if ID in column C = name in column J
for(z = 0; z < sheetNameArray.length; z++){ //looping through my sheets
if(name_master[x] == sheetNameArray[[z]]){ //if name in column K, which is of the same row as the key number
var copyrange = currentS.getRange("A"+y+2+":G"+y+2).getValues(); //y is the row in table 1 where the IDs are the same.
var destfile = ss.getSheetByName(sheetNameArray[[z]]); //copying to sheet Z.
destfile.getRange(destfile.getLastRow()+1,1,1,7).setValues(copyrange); //paste
}
}
}}}}
The thing that makes it easy is turning your small table into an object so that when the object is given the number in column 3 of the big table it returns the actual sheet object. The array pA in object sht provides you with the ability to check using indexOf() if the Sheet actually exists in the object without having to use hasOwnProperty().
function copyStuff() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
const objvs = sh.getRange(3,10,getColumnHeight(10,sh,ss)-2,2).getValues();
const vs = sh.getRange(2,1,sh.getLastRow() - 1,7).getValues();
let sht = {pA:[]};
objvs.forEach(r => {sht[r[0]]=ss.getSheetByName(r[1]); sht.pA.push(r[0])});//This creates an object which correlates enNo to a sheet making it possible to greatly simplify your code.
vs.forEach(r => {
if(~sht.pA.indexOf(r[2])) {//this determines if the sheet is defined in sht object if it is then you can do a copy because the sheet exists
let s = sht[r[2]];
if(s) {
s.appendRow(r);//this appends the entire row to the next empty row at the bottom of data. You could also use copyTo or setValues(). This is a simple approach.
}
}
});
}
Helper function: this function is used to the the height of column j. It's sort of the getLastRow() but only for a column:
function getColumnHeight(col, sh, ss) {
var ss = ss || SpreadsheetApp.getActive();
var sh = sh || ss.getActiveSheet();
var col = col || sh.getActiveCell().getColumn();
var rcA = [];
if (sh.getLastRow()){ rcA = sh.getRange(1, col, sh.getLastRow(), 1).getValues().flat().reverse(); }
let s = 0;
for (let i = 0; i < rcA.length; i++) {
if (rcA[i].toString().length == 0) {
s++;
} else {
break;
}
}
return rcA.length - s;
}
~ Bitwise Not
The easiest way to find information in the documentation is to use the index in it. Especially since they just changed it all and many of us no longer know where everything is.
SUGGESTION:
Since you want to check the large table A:G & then copy each table data that matches every user ID on the second table J:K and move those matched rows to the designated sheet named after the IDs' user names, you can refer to this sample implementation below:
function copystuff() {
var ss = SpreadsheetApp.getActiveSheet();
var main =SpreadsheetApp.getActiveSpreadsheet();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sheetNameArray = sheets.map(function(sheet){
return [sheet.getName()]});
var lastRowK = ss.getRange(ss.getLastRow(),11).getNextDataCell(SpreadsheetApp.Direction.UP).getRow(); //Get the last row of column K on any worksheet
var user = main.getSheetByName(sheetNameArray[0]).getRange("J3:K"+lastRowK).getValues();
var tableData = main.getSheetByName(sheetNameArray[0]).getRange("A2:G"+main.getLastRow()).getDisplayValues();
var container = [];
for(x=0; x<user.length; x++){ //Loop every user from the second table
for(y=0; y<tableData.length; y++){ //loop through the large table data
if(tableData[y][2] == user[x][0]){ //check each user's ID if it has any matches on the user ID from the large table data
container.push(tableData[y]); //any matched row data from the large table will be placed temporarily on this container
}
}
if(container.length != 0){
Logger.log("User "+user[x][1]+ " with ID *"+ user[x][0] +"* has these data:\n"+container);
main.getSheetByName(user[x][1]).getRange(1,1,container.length,7).setValues(container);
}
container = []; //clean container for the next user
}
}
This script will get all table data and place them into an array variables user & tableData where it will be checked and processed to make the script run faster instead of live processing the sheet rows.
Sample Result:
After running the script, here are some of the results:
User name RJ with ID of 42:
User name May with ID of 7:
User name Angelo with ID of 25:
Here's the Log Results for review:

Looping through rows, get values, and add to total on another sheet

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);
}

Google Sheets Script - paste values based on time trigger

I'm trying to do a few things with a piece of script but cannot get it all down.
In row 2 of my sheet I have a series of consecutive dates based on the first of each month (British notation) e.g 01/08/2016, 01/09/2016, 01/10/2016. I then have a formula in rows 14 and 15 which I would like to be fixed (copy / paste value) when today's date matches that in row 2.
I feel that I need to run a few things -
Schedule a script to run once per day to check if any value in row 2 is equal to today's date. If true then...
Copy / paste values of the numbers in rows 14 and 15 and the column where the date matches.
Maybe an index/match is needed to verify part 1 but I'm really in the dark on how to do it.
Thanks for any assistance.
I think that I've now managed to crack it. In row 1 I have put in a helper formula which checks the date in row 2 against today's date and puts "TRUEMONTH" in the cell if it matches. My clunky code is then as follows (it still needs some tidying up for the sheet refs etc) -
function ColCheck() {
var name = "TRUEMONTH";
var name1 = "PASTE_ME_AS_VALUE";
var range = SpreadsheetApp.getActiveSheet().getDataRange()
var values = range.getValues();
var range1 = SpreadsheetApp.getActiveSheet().getDataRange()
var values1 = range1.getValues();
for (var row in values) {
for (var col in values[row]) {
if (values[row][col] == name) {
for (var row1 in values1) {
for (var col1 in values1[row1]) {
if (values1[row1][col1] == name1) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var row = parseInt(row1) + 1;
var col = parseInt(col) + 1;
var source = ss.getActiveSheet().getRange([row],[col]);
source.copyTo(ss.getActiveSheet().getRange([row],[col]), {contentsOnly: true});
}
}
}
}
}
}
}

GoogleScript delete my HYPERLINK (Google SpreadSheet)

Situation:
I have the following script, that run every 1 hours. This script insert "Update Age", I mean how many days past from DATE1 to DATE2.
Script 1: Script Link
Problem:
Column A: This column have an hyperlink. (Tickets# Numbers)
Column F & G: Date 1 and Date 2
Column H: The result of the Script 1
In the coulmn A, I have other script that insert Hyperlink... See Script Link 2.
This Script 2, run OnEdit but the Script 1 run every 1 hour.
When the script 1 run, the formula or Hyperlink is deleted only appear the data in cell.
Question:
Does exist any way that when the script 1 run, not delete the hyperlink or apply the hyperlink to all rows starting for the second 2 rows, the hyperlink.
SCRIPT FOR INSERT LINK:
function InsertLink(e)
{
var actSht = e.source.getActiveSheet();
if (actSht.getName() == ['ISP1']){
var activeCell = actSht.getActiveCell(); //Detec the ActiveCell
//var activeCell = event.range;
var activeCellValue = e.value;
var column = activeCell.getColumn();
var colNums = [1]; //Columns, whose edit is considered
if(colNums.indexOf(column) == -1) return; //If column other than considered then return
var row = activeCell.getRow();
if(row < 2) return; //If header row then return
var length = String(activeCellValue).length;
if (!e.value)
{
activeCell.setValue()
}
else if(length > 2)
{
activeCell.setValue('=HYPERLINK' + '("https://www.example.com/id='+activeCellValue+'";"'+activeCellValue+'")');
}
}
}
SCRIPT UPDATE:
// Create a timer trigger that will call "shellUpdateAge" every 30 minutes
// This function will run only for this particular sheets
function shellUpdateAge(){
var sheets = ['ISP1'];
for (var s in sheets){
toUpdateAge(sheets[s]);
}
}
function toUpdateAge(sheetName){
var ss = SpreadsheetApp.openById('1WmEwSLzqxOj7xkjokmor5B_HpMdabbEAGXiYeQwpIl8');
var sh = ss.getSheetByName(sheetName);
var data = sh.getRange(1,1,sh.getLastRow(),sh.getLastColumn()).getValues();
for(var n=0;n<data.length;++n){
if(typeof(data[n][6])=='object'){
data[n][7]=dayToToday(data[n][6])
}
}
sh.getRange(1,1,data.length,data[0].length).setValues(data)
}
function dayToToday(x){
var refcell = x;;// get value in column A to get the reference date
var refTime = new Date(refcell);
var ref = refTime.setHours(0,0,0,0)/(24*3600000);// set hours, minutes, seconds and milliseconds to 0 if necessary and get number of days
var today = new Date();
var TD = today.setHours(0,0,0,0)/(24*3600000);// set hours, minutes, seconds and milliseconds to 0 if necessary and get number of days
var day = parseInt(TD-ref);// get the difference in days (integer value )
return day ; // return result that will be in cell
}
DATA:
A2: =HYPERLINK("https://www.example.com/id=12345";"12345")
Note: The Hyperlink appear for every row in the column A when I ingress the Ticket ID.
F: 12/08/2014 18:08:00 (This Value is the DATA2)
G: 13/08/2014 18:08:00 (This Value is the DATE2)
H: The update age, insert the result from DATE2-DATE1. In this example the script will return 1 day.
Now the problem is when the script Update Age run, the script update the column G and delete the formula in column A.
I would just get and set the bare minimum, so you're not involving the HYPERLINK column:
function toUpdateAge(sheetName){
var ss = SpreadsheetApp.openById('1WmEwSLzqxOj7xkjokmor5B_HpMdabbEAGXiYeQwpIl8');
var sh = ss.getSheetByName(sheetName);
var range = sh.getRange(1,7,sh.getLastRow(),2);
var data = range.getValues();
for(var n=0;n<data.length;++n){
if(typeof(data[n][0])=='object'){
data[n][1]=dayToToday(data[n][0]);
}
}
range.setValues(data);
}
As an aside, you wouldn't consider a spreadsheet array formula for the date difference and HYPERLINK columns?

Automatically move data from one sheet to another in google docs

i have a spreadsheet that i keep track of tasks i need to do, once complete i enter a date in the last column. What i want is for that completed task to be moved to sheet 2.
At present i have sheet 1 named SUD_schedule and i want the completed row of data to be moved to sheet 2 named SUD_archive. I've looked through the forum posts already and i've tried a variation of scripts but so far no luck. The closest i have come is this script:
function onEdit() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();//Original sheet
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];//target sheet
// to act on only one sheet, check the sheet name here:
//If it si not first sheet, it will do nothing
if (sheet1.getSheetName() != "SUD_schedule") {
return;
}
//Get Row and column index of active cell.
var rowIndex = sheet1.getActiveRange().getRowIndex();
var colIndex = sheet1.getActiveRange().getColumnIndex();
//If the selected column is 10th and it is not a header row
if (colIndex == 16 && rowIndex > 1) {
//Get the data from the current row
var data = sheet1.getRange(rowIndex,1,1,9).getValues();
var lastRow2;
(sheet2.getLastRow()==0)?lastRow2=1:lastRow2=sheet2.getLastRow()+1;
//Copy the data to the lastRow+1th row in target sheet
sheet2.getRange(lastRow2,1,1,data[0].length).setValues(data);
}
}
Column P (16) is the task complete date, row 1 is frozen and contains column headers.
Can anybody help show where i'm going wrong.
Kind regards
Den
Your code is not generic and you are more complicating your objective. Below will work out your need.
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName('SUD_schedule');
var sheet2 = ss.getSheetByName('SUD_archive');
var dateColumn = "16";
var array = []
var range = sheet1.getRange(1, 1, sheet1.getLastRow(), dateColumn);
for (var i = 2; i <= sheet1.getLastRow(); i++) //i iterates from 2 as you say R1 is header
{
if(isValidDate(range.getCell(i, dateColumn).getValue()) == true) //checking if any values on column16 is valid date
{
data = sheet1.getRange(i, 1, 1, dateColumn).getValues(); //Getting the range values of particular row where C16 is date
for (var j = 0; j < dateColumn; j++) //Adding the row in array
{
array.push(data[0][j]);
}
}
if(array.length > 0)
{
sheet2.appendRow(array); //Appending the row in sheet2
array = [];
sheet1.deleteRow(i); //deleting the row in sheet as you said you want to move, if you copy remove this and next line
i=i-1; //managing i value after deleting a row.
}
}
}
//Below function return true if the given String is date, else false
function isValidDate(d) {
if ( Object.prototype.toString.call(d) !== "[object Date]" )
return false;
return !isNaN(d.getTime());
}
I am not sure that the syntax you have as used below is entirely correct.
(sheet2.getLastRow()==0)?lastRow2=1:lastRow2=sheet2.getLastRow()+1;
sheet2.getRange(lastRow2,1,1,data[0].length).setValues(data);
What I know will work for certain is if you omit the variable lastRow2 all together and use this instead.
sheet2.getRange(getLastRow+1,1,1,data[0].length).setValues(data);
To complement Joachin's answer, here is how you can adapt that code if you don't have the date in the last row. In the below shown part of the code replace Lastcolumnumber with your last column.
//Getting the range values of particular row where C16 is date
data = sheet1.getRange(i, 1, 1, LASTCOLUMNNUMBER).getValues();
//Adding the row in array
for (var j = 0; j < LASTCOLUMNNUMBER; j++)