getLastRow() stops at row 68 - javascript

I have this function that is supposed to pull form data from one sheet then add it to another but it stops at row 68.
function fData(){
const os = SpreadsheetApp.openById("ID of Sheet with data to copy");
const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Data");
const dataToCopy = os.getSheetByName("Form Data").getRange(1,1,os.getLastRow(),7).getValues();
const dataDst = ss.getRange(1,1,os.getLastRow(),7).clearContent().setValues(dataToCopy);
// Logger.log(dataToCopy);
}
When I change os.getLastRow() to 192 in both locations where it appears in the function, all the information is copied over correctly. I would like to not have to specify the number of rows every time I run the function.
I think there is something wrong with my implementation of getLastRow() or the fact that both the copy and paste sheets share the same name but I am unsure if that is what causes the issue.
Here is the solution that got the desired result. There might be a better way but this worked.
function fData(){
const os = SpreadsheetApp.openById("ID of Sheet with data to copy");
const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Data");
const dataToCopy = os.getSheetByName("Form Data").getDataRange().getValues();
const lr = os.getSheetByName("Form Data").getDataRange().getLastRow();
const dataDst = ss.getRange(1,1,lr,7).clearContent().setValues(dataToCopy);
// Logger.log(dataToCopy);
}
I used getDataRange to pull the data, then defined lr as the last row of that data set. If you just replace the first instance of getLastRow with getDataRange you run into an error in which the target range and data set do not match in rows and columns and the function with push an error.

getLastRow(): this will get the last row in a Google Sheet that has data in it. It determines the last row based on the last available row value in all columns in the spreadsheet.
getDataRange(): this will get the range up to the last row and column with values in it.
Use getDataRange() instead. One of your columns must not have data in row 68.
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getdatarange

Related

How Do I Copy Non-Adjacent Cell Values to a Row for a Log Sheet?

I want to copy three cells, which are non-adjacent (AA9, AA12, and AA15), and paste them on another sheet in a single row, like a log sheet. (A2,B2,C2) I'm using "getLastRow+1" to make this happen. Currently, I'm only able to use getValue and setValue for a single cell (AA9) and after searching for similar examples online, I'm still struggling to make this work.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Main")
var destSheet = ss.getSheetByName('Log');
// Get the Cell Values from Main Sheet
var streak = sheet.getRange('AA9').getValue();
// Set the Values on Log Sheet
destSheet.getRange(destSheet.getLastRow()+1,1).setValue(streak);
I'm struggling to understand how to correctly implement what I want. I essentially want to copy the values in AA9, AA12, and AA15, and paste them (or use setValue) in A2,B2, and C2 on the other sheet.
I'm slowly learning and getting a better understanding of everything, and examples from google searches have gotten me far, but this is a headscratcher for me.
I've tried using Named Ranges, but I didn't understand how to find the last EMPTY row of that named range.
I've tried creating an Array for those cells, but didn't understand how to use SetValues correctly (got an error about the number of rows not being equal to the data rows, something like that)
// THIS DIDN"T WORK
var results = ['AA9','AA12','AA15'];
var streak = sheet.getRangeList(results).getRanges().map(range => range.getValues());
destSheet.getRange(destSheet.getLastRow()+1,1).setValues(streak);
I've also searched google quite a bit, and while the results have helped me script a random number generator (not shown here), I still struggle with more basic tasks.
You can make your latter code example work by using Range.getValue() instead of Range.getValues().
To easily append the values to the destination sheet, use Sheet.appendRow(), like this:
const sheet = ss.getSheetByName('Main');
const destSheet = ss.getSheetByName('Log');
const data = sheet.getRangeList(['AA9', 'AA12', 'AA15'])
.getRanges()
.map(range => range.getValue());
destSheet.appendRow(data);
Try it this way:
function myfunk() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const dsh = ss.getSheetByName('Sheet1');
const [a,,,b,,,c] = sh.getRange("AA9:AA15").getValues().flat();
dsh.appendRow([a,b,c]);
}
When I use getValues, it works perfectly! But it does throw an error, saying "Exception: The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues.". But again, it does actually work on my spreadsheet.
When I use getValue, it strangely works, and doesn't throw an error, it sets the values appropriately in an appended row, but then loops back around again and repeatedly sets the value in the first cell again, albeit one row down (because it just filled the previous row so it moves down). It's so strange. I can see it do it slowly, it sets the values in the row, a split second later it loops back to the first value, but one row down, and sets that value again. But none of the other ones.
If you can visualize this, it'll post 3 numbers, correctly, appended in the row, then one row down it'll post only 1 number, but leave the other two blank.
Screenshot Example
function log_data() {
const data = sheet.getRangeList(['AA9','AA12','AA15'])
.getRanges()
.map(range => range.getValue());
destSheet.appendRow(data);
destSheet.getRange(destSheet.getLastRow()+1,1).setValue(data);
}

Automating named Range function in google sheets

Context
So I have a spreadsheet with 11+ sheets, though will be adding more later. I want to dynamically name the columns using named range. I created a macro script and have been using this. Only the problem is for every sheet, I have to go to the script and change the name of the named range:
function NamedRanges() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setNamedRange('TrainlineDate', spreadsheet.getRange('A:A'));
spreadsheet.setNamedRange('TrainlinePrice', spreadsheet.getRange('B:B'));
spreadsheet.setNamedRange('TrainlineReturns', spreadsheet.getRange('C:C'));
spreadsheet.setNamedRange('TrainlineGrossReturns', spreadsheet.getRange('D:D'));
spreadsheet.setNamedRange('TrainlineGeometricReturns', spreadsheet.getRange('E:E'));
spreadsheet.setNamedRange('TrainlineRisk', spreadsheet.getRange('F:F'));
spreadsheet.setNamedRange('TrainlineNegativeReturns', spreadsheet.getRange('G:G'));
spreadsheet.setNamedRange('TrainlinePositiveReturns', spreadsheet.getRange('H:H'));
spreadsheet.setNamedRange('TrainlineTimeValueMoney', spreadsheet.getRange('I:I'));
};
For example, for the next tab, I have to change Trainline to Softcat.
I tried my hand at creating the columns as an array and then a for loop to create a named range according to the name in cell B2 + the name in the headers (the 3rd row of every column). I will also be adding new columns in the future. But when I tried to log the value in cell B2 it failed. Long story short, I am stuck. This is what I came up with thus far;
function NamedRange() {
const ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var col = ss.getLastColumn(); //Get all the columns in the sheet with data (there will be no gaps/spaces)
var stockName = ss.getRange("B1"); // name in cell B1 (column 2, row 1)
var headerCell = ss.getRange(3, col); // in row 3 of all columns
var rangeName = ss.getValue(stockName);
Logger.log(rangeName) // test to see if the value of stockname is picked up by Appscript
// For every column, get the values in 'stockName and headerCell' and create a named range from them.
An exception is for the second column, instead of 'Close' name, call it 'Stockname' + 'Price'.
};
Here is an example of the spreadsheet format. This script though will be applicable to Aveva Group tab onwards.
Problem
Typically the format of the spreadsheets will all be the same. The only difference will be the name of the stock. I want to be able to automatically set the namedRange of all columns for existing and new columns for every tab/sheet and trigger it using a custom menu (this part I can sort out myself). Is there a better way to get this done?
Explanation:
Create an array of all the sheet names you would like to be part of this process.
ForEach sheet name, set the name ranges according to that name by concatenating the sheet name with the namerange name.
Solution:
function NamedRanges() {
var spreadsheet = SpreadsheetApp.getActive();
//put all the sheets here you want to include
var sheetNames = ["Trainline","Softcat","Avast"];
var namerng=['Date','Price','Returns','GrossReturns','GeometricReturns',
'Risk','NegativeReturns','PositiveReturns','TimeValueMoney'];
sheetNames.forEach(sh=>{
sheet = spreadsheet.getSheetByName(sh);
namerng.forEach((nr,i)=>{
spreadsheet.setNamedRange(sh+nr, sheet.getRange(1,i+1,sheet.getMaxRows(),1));
});
});
};
Save also this code to your script editor and it will create a menu button at the top menu of the spreadsheet file that will execute NamedRanges:
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Custom Menu')
.addItem('Name Ranges', 'NamedRanges')
.addToUi();
}

Copy filtered range from one spreadsheet to another - Google app script

I have a large google sheet with 30275 rows and 133 columns in a google sheet. I want to filter the data and copy column AZ to another spreadsheet.
Link to spreadsheet: https://docs.google.com/spreadsheets/d/1aiuHIYzlCM7zO_5oZ0aOCKDwPo06syXhWvhQMKgJE2I/edit?usp=sharing
I have been trying to follow this link
I am not that familiar with javascript and the code is designed to exclude items from filter rather than including items on filter. I have 500+ items to exclude so need to work out something that will be efficient in filtering large dataset in short time before execution limit is reached.
Here is my code so far. Any help to get this working would be appreciated.
NOTE: Filter/ Query with importrange formulas dont work due to the large volume of data. So I need an efficient script to filter large dataset and move them to another sheet before execution time limit.
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
var destsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('JockeyList');
var demosheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValues();
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here
//Logger.log(jockey);
var hiddenValues = jockey;
values = values.filter(function(v) {
return hiddenValues.indexOf(v[51]) == 1;
});
Logger.log(values.length);
// Set filtered data on the target sheet
destsheet.getRange(10, 5, values.length, 2).setValues(values);
}
Ok so it seems like you want to copy only the values from AZ in 'Sheet1' that are equal to whatever string value is contained in cell L14 of sheet 'Betting data - Demo.' If that is the case, then here is a change to your original code that will accomplish that:
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
// this assumes that your destsheet and demosheet are in the same spreadsheet. Keep in mind that opening spreadsheets with SpreadsheetApp is costly so you want to minimize your calls to new sheets.
var destsheet = ss.getSheetByName('JockeyList');
var demosheet = ss.getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValue();
var searchTerm = new RegExp(jockey);
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here and return ONLY THE VALUE IN COLUMN AZ
var filteredValues = values.reduce(function(resultArray, row) {
if (searchTerm.test(row[51])) resultArray.push([row[51]]);
return resultArray;
}, [])
// Set filtered data on the target sheet
// Note* not clear why you are starting at row 10, but as is this will overwrite all of the data in column 5 of destsheet starting from row 10 every time this function runs
destsheet.getRange(10, 5, filteredValues.length, 1).setValues(filteredValues);
}
As it says in the code sample, this will only copy and paste the value in column AZ of 'sheet1'. It does not alter 'sheet1' in any way. If that is really all you want to do, then this function works, but it's overkill. Since you are just filtering values in AZ against a single string value, it would be more efficient to simply count the number of times that string occurs in column AZ and then add the string that number of times to your destination sheet.
Also note that your original function is pasting values into destsheet into a constant row (row 10). That means that every time your function runs, the data from row 10 on will be overwritten by whatever data you are copying from 'sheet1'

Previously Copied range values being over written by newly copied data

Previously Copied range values being over written by newly copied data
There are 4 pars to the function I am developing.
Part 1: copies a row of data starting from row “i” located in range “Ai:Pi” – where i = the row number, one at a time, to a different location – range “A5:P5” (I have called input data staging range) on the same sheet. WORKS FINE
Part 2: The data from the staging range is then pulled into another spreadsheet for processing. WORKS FINE
Part 3: The processed data from the other spreadsheet is then copied back into the original spreadsheet – range “T5-AA5” (which I have called processed data staging range). WORKS FINE
Part 4: I then want to copy the VALUES only from the range “T5:AA5” to the same row “i” as the input data, so that the range to be copied is “Ti:AAi”. NOW WORKING.
I have tested what I am looking to do in Excel and it works perfectly well when I am using PASTE SPECIAL However in Google Apps the problem is that whilst the values are copied to the right row “i”, they get over written by the new range of data to be copied.
I really want to resolve PART 4.
My code is:
function getRowReturnValue() {
// "Form Responses 1" is the sheet with the Forms Data.
// The "Simple loop testing" sheet was set up to test the development of teh Apps scripts.
// Spreadsheet Sources
var ss = SpreadsheetApp.getActiveSpreadsheet();
var processor = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1fuGpv7YsyM5sCAMC25UkpfEURm06fJjyieezY3CjMl4/edit")// This is the PROCESSOR spreadsheet where
// Data source sheets in the source spreadsheets
// NOTE: IF YOU CHANGE THE SHEET NAME, THEN YOU NEED TO CHANGE TH SHEET NUMBER IN THE SQUARE BRACKETS BELOW FOR SOURCE and DESTINATION variables
// [0} = sheet 1 = "Form Responses 1"; [1] = "Test Sheet"; [2] = "Simple loop testing"
var spr = ss.getSheetByName("Form Responses 1")
var processorOutputData = processor.getSheetByName("MASTER OUTPUT");
var source_sheet = ss.getSheets()[0]; // This is the location sheet of the FORMS INPUT data. In this case the "[0]" indicates the position of the very first sheet in the source spreadsheet
var target_sheet = ss.getSheets()[0]; // This is the location sheet of the PROCESSED data from the processor. In this case the "[0]" indiates the position of the very first sheet in the
// source spreadsheet
// Identify the number of rows of Forms Input data to be processed.
var lastDataRow = spr.getLastRow(); // NOTE: This rule is identifies the last low number, ignoring blank rows in between. The disadvantage is that it looks at the WHOLE row and not just
// the cells of the row into which the Forms Input data will occupy
Logger.log(lastDataRow); // CHECK
var NumbOfResponses = spr.getLastRow(); // CHECK
Logger.log(NumbOfResponses); // CHECK
// Clear the content of the staging row
var clearStagingRow = spr.getRange(5,1,1,16);
clearStagingRow.clearContent();
for (var i = 10; i<NumbOfResponses+1;i++) {
// Extract the input data VALUES, row by row, to be processed from the source sheet and put it into the INPUT STAGING area - which holds one row of data at a time.
var values = source_sheet.getRange(i,1,1,16);
values.copyValuesToRange(target_sheet, 1, 16, 5, 5); // Once the data is in the INOUT STAGING area, it is imported to the "MASTER OUTPUT" sheet in the processor spreadsheet.
// This data is then processed and the resulting output data is posted in a range ready to be copied back into
// the "Forms responses 1" sheet
// Identify the source range from the "MASTER OUTPUT" processor sheet. Identify the target range in the PROCESSED STAGING range in the "Forms responses 1" sheet
var processedData = processorOutputData.getRange("d43:k43").getValues(); // Identify the range in the "MASTER OUTPUT" from where the data is to be sourced
var target_range = target_sheet.getRange("T5:AA5").setValues(processedData); // Identify the target range in the PROCESSED STAGING area where the input is to be put
// Copy PROCESSED OUTPUT data from OUTPUT STAGING range to the row alligned to the input data
var retValues = source_sheet.getRange(5,20,1,8);
retValues.copyValuesToRange(target_sheet, 20, 27, i, i);
// Clear out the data previously copied into the OUTPUT STAGING data
target_range.clearContent();
}
}
I have reviewed and redesigned the model and fortunately the simplicity has resolved the issue. The code that works well is
var source_range = source_sheet.getRange(i,1,1,16); // identify range and location where data is sourced
var source_values = source_range.getValues(); // get thevalues in the location
var target_range = target_sheet.getRange(8,4,1,16); // identify the range and location of where the data is to be copied in the processor
target_range = target_range.setValues(source_values); // copy the values in the target range and location in the processor
var targetoutput_range = target_sheet.getRange(38,4,1,8); // identify range and location of where the processed data is
var targetoutput_values = targetoutput_range.getValues(); // get the output values
var destoutput_range = source_sheet.getRange(i,18,1,8); // identify the range and location of where the output data will be copied
destoutput_range = destoutput_range.setValues(targetoutput_values); // copy the output values in the destination range and location
I run the above in a loop and that posts output values in the same row as input data.
The issue that I have is that as the number of inout rows gets large, the time taken for the data to be processed is increasing.
My answer was to have the only the new rows evaluated and the 'older' rows left untouched. My code for this works but the time taken does not happen to be shortened.
So if there are suggestions on how I can shorten the time then please recommend.

How to retrieve data column-wise in Spreadsheets

I have a spreadsheet with a lot of data. I need to retrieve this data column-wise (or row-wise if column-wise is too complicated). However I can't figure out a way to do this. I have the following working function which returns the data contained in a specific rectangular grid in the spreadsheet specified by row number, column number, number of rows, number of columns.
However, what I want to do, is simply mention the column number and get all the data in that column.
function getSpreadSheetData(){
var id= SpreadsheetApp.getActiveSpreadsheet().getId();
var ss = SpreadsheetApp.openById(id);
var sheets = ss.getSheets();
// the variable sheets is an array of Sheet objects
var sheetData = sheets[0].getRange(row, column, numRows, numColumns);
//consider row,column,numRows,numColumns = 2,1,2,2
return sheetData;
}
How should I modify this code?
How do you want to return it and to what?
it seems what you are trying to achieve can easily be done with:
function getSpreadSheetColumns(sheetName, c){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
return ss.getRange(1, c, ss.getLastRow()).getValues();
}
Possibly moving the sheet name inside the function if it will always be the same.

Categories

Resources