Copying and pasting data in Google Sheets to another column - google-apps-script

I have a dashboard that is reporting live data based on a growing customer database, and I am currently tracking the daily process by copying and pasting the data in the column into the next on a daily basis.
I'd like to create a script that automatically copies the values from an array (B:B) for example, into another sheet OR into the next available column to the right.
You may refer to the image below for further clarity.
Sample
I saw may threads on this but they were all about copying into a different row, as opposed to a different column.
Many thanks in advance!

The getLastRow() method is used to return the position of the last row that has content.
The getLastColumn() method is used to return the position of the last column that has content.
Therefore, in order to be able to copy the data into the next available column, I suggest you try this:
function copyColumn() {
var ss = SpreadsheetApp.openById("ID_OF_THE_SPREADSHEET");
var sheetFrom = ss.getSheetByName("SHEET_FROM");
var sheetTo = ss.getSheetByName("SHEET_TO");
var values = sheetFrom.getRange(NO_OF_THE_ROW_WHERE_DATA_STARTS, 3, sheetFrom.getLastRow(), 1).getValues();
sheetTo.getRange(NO_OF_THE_ROW_WHERE_DATA_STARTS,sheetTo.getLastColumn()+1,values.length,1).setValues(values);
}
The above script localizes all the data that needs to be copied by using the getRange() method and is copied by using getValues().
NO_OF_THE_ROW_WHERE_DATA_STARTS is the value representing the number of the row where your data starts (in your case the row of No of LP - Secured);
3 is the value representing the C column (where the data you want to be copied is located);
sheetFrom.getLastRow() is the value representing the end of the data you want to be copied;
1 is the value representing the number of columns that need to be copied.
Afterwards, the getRange() method is used again in order to be able to identify where the data needs to be pasted and setValues() in order to actually paste it.
Note: The above script works for different spreadsheets and/or different sheets OR for sheets in the same spreadsheet. If you want to use it for the latter case, you just have to put the name of your sheet instead of SHEET_FROM and SHEET_TO.
Moreover, I suggest you check the following links since they might be of help:
Sheet Class Apps Script - getRange();
Range Class Apps Script - getValues();
Range Class Apps Script - setValues();
Sheet Class Apps Script - getLastColumn();
Sheet Class Apps Script - getLastRow();

Related

I want to transfer the content from one spread sheet to another spreadsheet(spreadsheet A to spreadsheet B) and also to enter records to B manually

I want to transfer the contents from one spreadsheet to another spreadsheet(spreadsheet A to spreadsheet B) whenever if I do changes in spreadsheet A it has to be reflected in spreadsheet B. At the same time, I should also be able to add elements directly to spreadsheet B. I tried importrange function, it was transferring the contents from A to B but it is not allowing me to manually add things to spreadsheet B.
The best approach you could take for this is to use Apps Script.
Some methods which can be of help to you:
openById - which is used to retrieve each spreadsheet by their ids;
getSheetByName - which is used to retrieve the sheets from the spreadsheets;
getRange - which is used to retrieve the range in which the values can be found;
getValues - which is used to retrieve the values from the specified range;
setValues - which is used to place the values to the specified range;
Moreover, if you want to have the changes from one spreadsheet reflected on another, you can also make use of an onEdit trigger.
Reference
openById(id);
getSheetByName(name);
getRange();
getValues();
setValues(values);
onEdit(e).

Using setformulas to copy both values and formulas down a column

PROBLEM: In the below spreadsheet, cells C12:C17 (green) contain text imported from another spreadsheet (The "PARENT").
https://docs.google.com/spreadsheets/d/1brm0dHkXG1vxn2NQ7wGvEoayCdGYKsY4yA-MX4Jtt1w/edit#gid=396314711
Some cells have text. Some are blank. Some contain simple math (i.e 1+1), and others relational math (i.e. A1+B1). The DATA SET in the PARENT sheet are different than the CHILD sheet. I will eventually have to create a lot of CHILD sheets, each with their own unique DATA SET. The formulas on the PARENT sheet will change from time to time, so the solution isn't to just make a copy of the PARENT spreadsheet and turn it into a CHILD sheet.
I need to be able to create the formulas in the PARENT sheet, but when imported into the CHILD sheet, they need to be calculated using the data set on the CHILD sheet.
I'm trying to use a script that will take what is in the C12:C17 range, and make it an active formula in the corresponding D12:D17 cells. If the C column cell is a value, it should just put that value in there instead of making it into a formula.
I've made about a dozen attempts at the setFormulas script. All failed. At this point, I would say I'm "spit-balling", "flailing", and possibly "spiraling". The BEST I've been able to do is to get ONE cell to update (but only if a formula, not text).
I'm looking for a script that will take whatever is in cells C12:C17, and execute/evaluate them into cells D12:D17. If there are text/values in the C cell, then it should put that text/value in the corresponding D cell. If there is a formula in the C cell, it should make it execute in the corresponding D cell. There is no pattern on whether a cell will be a number, text, or formula.
I appreciate any help you can give.
FYI: The formulas/text in the C column were made by importing from the PARENT sheet. That range of cells in the PARENT sheet was made by the following formula:
=IFERROR(FORMULATEXT('P CUSTOMERS'!B12),'P CUSTOMERS'!B12)
Essentially, "If it's a formula, convert it into text. If it's not a formula , just put what is in the cell in the first place ."
I've been working on this for an embarrassing amount of time... (Not hours, not days, not weeks, but MONTHS!).
EDIT / UPDATE:
OK, Marti's scripts worked great in the example file. Moved it to another file, same conditions, and worked again.
THEN, I moved it to another file... Only difference I can tell is that it is MUCH larger.
EDIT SUMMARY:
Ran the script under these conditions.
Made table with formulas. Used FORMULATEXT on that table to convert into text. Imported that range to another sheet. Used an HLOOKUP formula to select which column I wanted to look at formulas for.
In the sample sheet (linked here: https://docs.google.com/spreadsheets/d/1cPSJMXNiKDnHCiUCGJ0iSjaoIiRLQldr1T5rClUUEm0/copy), it works.
But when I run the exact same series of events in another sheet, it fails to do anything. Process is the same, only the range is different. No other scripts on this sheet.
I trimmed down the second sheet so I can share (script still doesn't work).
https://docs.google.com/spreadsheets/d/1RRMy4RtF9CVSXw18bWg79Dh4nwHg8IN3wwhLb3QynvA/edit#gid=236899042
(Note: I can't force a copy, as this sheet requires authorizations from another file)
Here is a video better explaining the issue:
https://drive.google.com/file/d/1pjz_LilRReQlNt7p_4NhU3prtbcAhLah/view?usp=sharing
So, I'm trying to understand why it works in one, but not the other... And just as important, what can I do to make it work in 2nd sheet, which is actual goal.
You can simply use getValues together with setValues. setValues actually interprets values starting with = as formulas, and getValues actually doesn't add the ' before them. So you can simply chain them:
function computeValues() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const s = ss.getSheets()[0]
const src = s.getRange('C12:C')
const target = src.offset(0, 1)
target.setValues(src.getValues())
}
References
Range.getValues() (Apps Script reference)
Range.setValues(values) (Apps Script reference)
Range.offset(rowOffset, columnOffset) (Apps Script reference)
Martí nailed it...
function computeValues() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const s = ss.getSheets()[0]
const src = s.getRange('C12:C')
const target = src.offset(0, 1)
target.setValues(src.getValues())
}
I tested it, as written, by copy/paste. Worked 1st time.
I added in more formulas below the original range, just to see what the limits were (in cell C20), and re-ran it. Still worked.
I would have kept going in my setFormula direction for another few months. Not sure how I got it stuck in my head that was the only solution. This was the final major barrier in my project, and while I still have another few years of manual data entry and formula creation to do, THIS will be the key that makes it all work. THANK YOU!!!

Google Apps Script- Copy & paste data from column one row at a time

(Please note: JavaScript, Stack Overflow posting, & Google Script novice)
THE BACKGROUND: I'm attempting to use a Google Sheet Email Notification Add On to trigger notifications when a specific value is seen in a Google Sheet. The config requirements of the add on look for a TextValue, however it has trouble finding the value in a pivot table (where my data is sorted). I've tried moving the data to another sheet with a QUERY formula, however the resultant value is not seen by the add on as a TextValue but rather a cell formula.
My workaround to this is to use a script to copy & paste the data from my pivot to a separate sheet. I used this post as my guide to create my script. It works, however because it pastes all column values at once, the add on is having trouble identifying the trigger TextValue.
THE QUESTION: instead of having the entire column copied and pasted at once, how can I tweak this script to copy and paste a row at a time with a slight delay (1-2 seconds)? This delay will allow the add on to see the the target TextValue and execute the notification (I've tested this manually and it works as expected). Any help in modifying this script (or completely changing the logic if necessary) would be greatly appreciated!!
//Copy contents of inventory column daily to run notification add on
function readInventoryNum() {
var sheetFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Inventory Totals");
var sheetTo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Testing123");
// Copy from 2nd row, 7th column, all rows for one column
var valuesToCopy = sheetFrom.getRange(2, 7, sheetFrom.getLastRow(), 1).getValues();
//Paste to another sheet from first cell onwards
sheetTo.getRange(1,sheetTo.getLastColumn()+1,valuesToCopy.length,1).setValues(valuesToCopy);
}

How to link various Google spreadsheets using IMPORTRANGEs that contain VLOOKUP formulas without getting #N/A returned?

The problem:
When using IMPORTRANGE to pull data from a different spreadsheet, cells in the origin spreadsheet that contain a formule containing VLOOKUP often (but not always) return #N/A (ERROR: Did not find value 'xxx' in VLOOKUP evaluation). In the origin sheet the formulas are calculated correctly and showing a value though. This does not always happen, sometimes it does pull in the proper value.
The intent:
To take data from different spreadsheets, combine them in a different spreadsheet and do some calculations on them. And then pull info from this calculation spreadsheet (or from multiple calculation spreadsheets) into a reporting spreadsheet for some further calculations and formatting.
The set-up:
There are several source data spreadsheets,say dataspreadsheet1, dataspreadsheet2 and dataspreadsheet3. A calculation spreadsheet (calcspreadsheet) is created that creates a copy of sheet1 in each of the data spreadsheets and names these sheets datasheet1, datasheet2 and datasheet3 respectively. The IMPORTRANGE statement used for this is created as follows: importrange(+VLOOKUP("dataspreadsheet1",filelist!A1:C1000,3,FALSE),"sheet1!a1:Z1000") where
filelist!A1:C1000 is a sheet in calcspreadsheet that contains Name, Type and Id in respective columns.
The values in each of these sheets datasheet1-3 are then used for calculations in another sheet, calcsheet1 in the calcspreadsheet. As the main goal of this is to add up daily values from the 3 dataspreadsheets, but those sourcesheets do not all have the same data on the same line a VLOOKUP is used again to make sure additions for a date use the line for the date in datasheet1-3 regardless of its row number. E.g. VLOOKUP($A11,'datasheet1'!$A:$P,4) + VLOOKUP($A11,'datasheet2'!$A:$P,4) + VLOOKUP($A11,'datasheet3'!$A:$P,4) where column A is the date column in all sheets.
This appears to work fine, although upon opening calcspreadsheet it can take a long time for it to go through an update, during which time lots of #N/A's are displayed. Eventually it comes right though.
The problem arise when a reportspreadsheet is created that in turn used an IMPORTRANGE call to pull the info from calcsheet1 in order to be able to work with it. This often, but not always, results in the problem states at the start. The IMPORTRANGE call in this reportspreadsheet is generated in a similar way as that in the calcspreadsheet: =importrange(+VLOOKUP(calc!B1,sheetcodes!A1:C3000,3,FALSE),"sheet1!a1:Z1000") where calc!B1 contains the name of the source spreadsheet (in this calc that would be 'calcspreadsheet' and sheetcodes!A1:C3000 again contains a list of sheets with Name, Type and Id in respective columns
A work-around I tried:
What I did notice that IMPORTRANGE works better on cells that do not contain VLOOKUP So I tried to copy the content of calcsheet to another sheet in calcspreadsheet, called exportsheet but having only the values in there, not formulas and then use IMPORTRANGE on this exportsheet. The copy script used is as follows:
function exportPrep() {
// Get the active spreadsheet and the active sheet
//var ss = SpreadsheetApp.getActiveSpreadsheet();
//var sheet = ss.getSheetByName("stream");
//sheet.activate();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("calcsheet");
var sourceDataRange = source.getDataRange();
var sourceSheetValues = sourceDataRange.getValues();
var sourceRows = sourceDataRange.getNumRows();
var sourceColumns = sourceDataRange.getNumColumns();
var destination = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(destination.setActiveSheet("exportsheet"));
destination.getDataRange().offset(0, 0, sourceRows, sourceColumns).setValues(sourceSheetValues);
}
This seemed to work, but unfortunately the copy script used to copy the value of calcsheet into exportsheet now showed the same behaviour, it would sometimes work and sometimes give the #N/A and so leaves me with the same problem.
My questions:
I've read various posts with similar issues and responses that mentioned this function was temperamental or had a bug. Other stated it is not possible to use dynamic references in IMPORTRANGE. Given that it sometimes works and sometimes not I suspect the function itself might be correct but that there are sync or time-out issues in the set-up.
How can I set up the above functionality. Either with the use of IMPORTRANGE and VLOOKUP at all with some changes/additions, or built in a different way from the get-go.
So I've not done this with importrange but I when I have this issue with Vlookup I wrap the vlookup in an IF and test for the #N/A.
Try something like: =IF(ISNA(VLOOKUP(...)),"",VLOOKUP(...))
=IFERROR(VLOOKUP(B81,'KAM_Q3_OPPS STAGE_(H/I/L/M/N)'!$F$3:$G$111,2,False),)
This is the best way I found to do it and the last two values [ , ) ] make the new output, in this case it is nothing.
IF you wanted 0 put in then you would do [ ,0) ]

Workaround for not losing cell's reference because of user doing sorting, while script checks cells value

I have been struggling with the following situation for almost the whole last week and it would be awesome if someone could give me some hint.
The situation:
1. Script finds a particular value in, lets say, 'Sheet1', and gets the row number of the cell containing this value.
2. Since script has found this value, it executes a bunch of actions like creating new spreadsheet and copying numerous 'Sheet1' from dozen other spreadsheets to this newly created spreadsheet, and comparing/ analyzing data.
The problem.
- While script is doing a bunch of other actions, user is able to rearrange cells by, for example, sorting A to Z, which changes the address of previously found cell.
Here is the code that I used in order to verify this:
function WhatHappensIfUserSorts () {
var ss = SpreadsheetApp.getActive();
var sh = ss.getActiveSheet();
var rng = sh.getRange("B17"); //Lets say that script finds this cell according to some rules
Utilities.sleep(10000);
rng.setValue("Test Value");
}
Question:
Might there be any workaround for this?
My current ideas.
1. I was thinking about hiding the filter row in the beginning of the script, but this doesn't help a lot, because users can insert new row in the which will change the addresses of the rows below.
The background.
I am trying to create two way synchronization, meaning, each project member has his/ her own spreadsheet with 'Project X', 'Project Y' etc. sheets and no matter who updates their project sheets, all other users that work on the same project get these updates in their project sheets. These updates that have to be tracked are not just the cell values, these are cell notes as well. And this is the reason why script has to do the bunch of other actions, since CopyTo method does not work between spreadsheets.
During my research I found sheetSpider project, but it seems somewhat different and too complicated from what I need.
A simple suggestion would be to give each row a unique identifier so that you could use it to evaluate the target range again before you write back to the sheet.
get target row's unique ID --> do work --> locate target rows ID and use to determine write range --> write back to sheet.
Alternatively, during the operation you could delete the target row and then use appendRow() to drop the updated version back in.
A third and final suggestion might be to temporarily suspend the permissions for the sheet. See: https://developers.google.com/apps-script/reference/spreadsheet/page-protection#setProtected