I have an array of data that looks roughly like this:
header row | header row | header row | header row
project | date | LastName, FName | hours
project | date | LastName, FName | hours
project | date | LastName, FName | hours
header row | header row | header row | header row
project | date | LastName, FName | hours
project | date | LastName, FName | hours
project | date | LastName, FName | hours
I'd like to strip the header rows out of the array. I thought I'd use ArrayLib.filterByDate to do this, thinking that any rows that did not contain a valid date in my timeframe would be stripped out.
Here's the code I tried:
function removeHeaders(projectRange){
var tmpProjectRange = [];
tmpProjectRange = ArrayLib.filterByDate(projectRange, 1, new Date(2013-01-01), new Date(2015-01-01))
return tmpProjectRange;
}
I get an error: "the selected column should only contain dates". So this method appears not to be an option.
Now, I'm trying to use ArrayLib.filterByText to compare column 2 to an array of valid data:
function removeHeaders(projectRange){
var tmpEmployeeRange = [];
var tmpEmployeeList = [];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var shtEmp = ss.getSheetByName("Employees");
var empLastRow = shtEmp.getLastRow();
var strRange = "A2:A" + empLastRow;
//should contain a list of all the employees:
tmpEmployeeList = shtEmp.getRange(strRange).getValues();
tmpEmployeeRange = ArrayLib.filterByText(projectRange, 2, tmpEmployeeList);
return tmpEmployeeRange;
}
But for some reason this is not working either. The only rows coming back in the tmpEmployeeRange are rows that have a name that does not have a comma (these rows have TBD rather than Last Name, First Name.) So I'm not really sure what is going on there, but I'm thinking that there has to be an easier way to do this. I guess I could just iterate through the entire thing and strip out the rows I don't want. Any other ideas?
If we assume that the logic of looking for rows with valid dates is correct, then it is very easy to iterate over the range and remove headers.
Here, I'm borrowing the isValidDate() function from Detecting an "invalid date" Date instance in JavaScript. I'm also keeping the first header row - you can get rid of that by removing the check for row == 0.
// Iterate over all rows, keeping the first header row and
// any row with a valid date in the second column.
function removeHeaders(projectRange){
var tmpProjectRange = [];
for (row in projectRange) {
if (row == 0 || isValidDate(projectRange[row][1])) {
tmpProjectRange.push(projectRange[row]);
}
}
return tmpProjectRange;
}
// From https://stackoverflow.com/questions/1353684
// Returns 'true' if variable d is a date object.
function isValidDate(d) {
if ( Object.prototype.toString.call(d) !== "[object Date]" )
return false;
return !isNaN(d.getTime());
}
Related
function dailyprofit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Matt");
var profit = SpreadsheetApp.getActiveSheet().getRange('O2').getValue();
sheet.appendRow([,,,profit ]);
}
Hello, i'm attempting to use appendrow to put my variable into the last blank cell of row D, however appendRow does the entre row rather than just column D.
i would like the "profit" to be appended to row 362 rather than row 363 -> see example here
Thanks!
You can use this sample code to get the last row of Column D:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Matt");
var profit = SpreadsheetApp.getActiveSheet().getRange('O2').getValue();
var colValues = sheet.getRange("D1:D").getValues();
var count = colValues.filter(String).length
sheet.getRange(count+1,4).setValue(profit);
What it does?
Get all the column D values using sheet.getRange("D1:D").getValues()
Filter the array with string values and get its length/count. Empty cells will not be counted.
Increment the column D count by 1 and use Sheet.getRange(row,column) to get the cell below the non-empty cell in Column D. Use Range.setValue(value) to set the cell value.
Sample Output:
NOTE:
This will only work assuming you don't have an empty row in Column D.
If you have empty rows in your Column D, you might need to add few more offsets when incrementing the count.
Example:
I have 2 empty header rows (rows 1 and 2). Therefore, the offset of row count should be +3.
Sample Code:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Matt");
var profit = SpreadsheetApp.getActiveSheet().getRange('O2').getValue();
var colValues = sheet.getRange("D1:D").getValues();
var count = colValues.filter(String).length
sheet.getRange(count+3,4).setValue(profit);
I've done a google doc template that I'm modifying on the basis of the inserted value in a google sheet.
I've this kind of problem, once I've defined the google doc document I've to remove some tables and I'm doing like this:
Var Table1 = body.getTables()[1];
Var Table2 = body.getTables()[2];
....
Var Table15 = body.getTables()[15];
Table1.RemoveFromParent();
Table2.RemoveFromParent();
...
Table15.RemoveFromParent();
All Works till the 10th Table, at the 11th an error box appear with
"TypeError: Impossible call the method "removeFromParent" of undefined
. It seems like app script cannot recognize Table from to 11st to the next ones.
But the weirdest thing is that I've tried to change the position of the tables in the doc and sometimes the script recognizes the tables between the 11 and the 15, others does not.
Any ideas?
Thanks
Suppose we have a document with 5 tables:
Logger.log(body.getTables().length) // Outputs: 5.0
var table0 = body.getTables()[0];
var table1 = body.getTables()[1];
var table2 = body.getTables()[2];
var table3 = body.getTables()[3];
var table4 = body.getTables()[4];
Once you do:
table2.removeFromParent();
Now
table4 is referencing something that does not exist anymore:
var table4 = body.getTables()[4];
is undefined, because there are know only 4 tables left:
Logger.log(body.getTables().length) // Outputs: 4.0
var table0 = body.getTables()[0]; //same
var table1 = body.getTables()[1]; //same
var table2 = body.getTables()[2]; //this is now table 3
var table3 = body.getTables()[3]; //this is now table 4
var table4 = body.getTables()[4]; //undefined, does not exist.
There are only 4 tables now: 0, 1, 2 & 3.
I have a script to move a row of data in an employee schedule spreadsheet (thanks to help from the Sheets reddit) it is working but has stopped finding one part of the data.
Spreadsheet here: https://docs.google.com/spreadsheets/d/10yLJ_NyFasGhlRt2LsXO2CC804Zf5JLvwUisgytQOhM/edit?usp=sharing
Once the Finished column 63 is set to "YES" it copies the data (only from the required columns), locates the employee's name based on whose week is marked "x" and moves them to the Finished Sheet.
The code used to work fully but now it isn't finding "x" or grabbing the employee's name.
I've had to update the column numbers in the script a few times as we've gotten more employees, it's possible I've broken it doing that.
(Any blank columns do have data in my real spreadsheet I've just left them blank here as it's not relevant to the script)
Would really appreciate any advice! Thank you!
[Full code in spreadsheet]
if (ecol == 63 && ssh.getName() == 'SCHEDULE' && rng.getValue() == 'YES') { //if Schedule!63 is YES
var data = []; //output data
var rowN = rng.getRow();
var rowV = ssh.getRange(rowN,1,1,63).getDisplayValues();
var row = rowV[0]; //get edited row
var colX = row.indexOf('x')+1; //find X
var offset = colX - ((colX-2) % 5 ) // offset to the first column
var emp = ssh.getRange(1,offset).getValue(); //get employee name
var dd = Utilities.formatDate(new Date(), "GMT+10", "dd/MM/yyyy") //generate date finished
data.push(row[1],row[2],row[3],dd,row[5],emp); //get row
dsh.appendRow(data); //move row
ssh.deleteRow(e.range.rowStart); //delete from schedule
}
}
I believe this var offset = colX - ((colX-2) % 5 ) // offset to the first column
should be this var offset = colX - ((colX+2) % 5 ) // offset to the first column
This is what's causing you to not find employees because the employees are in a merge group of cells which always puts it's value in the left most cell for horizontal merging.
Our client's online shop uses Opencart, for marketing purposes they wanted to sync Opencart orders automatically with Google Sheets. I modified a script in google sheets to extract customer orders from the past year (based on https://www.transpacific-software.com/blog/opencart-to-google-docs-pull-and-sync-data-auto-through-scripting and https://gist.github.com/pradeepbheron/e6129c9fd9bc74e814d0)
The SQL query is:
SELECT order_id, firstname AS first_name, lastname AS last_name,
email, date_added AS order_date, CONCAT("£", FORMAT(total,2))
order_value, payment_address_1 AS billing_address_1,
payment_address_2 AS billing_address_2, payment_city AS
billing_city, payment_postcode AS billing_postcode,
payment_country AS billing_country, items_purchased FROM
(
SELECT order_id, firstname, lastname, email, date_added,
total, payment_address_1, payment_address_2, payment_city,
payment_postcode, payment_country
FROM ocbw_order
GROUP BY order_id
) AS A
JOIN (
SELECT order_id AS product_order_id, GROUP_CONCAT(name
SEPARATOR ", ") AS items_purchased
FROM ocbw_order_product
GROUP BY product_order_id
) AS B
ON A.order_id=B.product_order_id
WHERE date_added >= DATE_SUB(NOW(),INTERVAL 1 YEAR)
AND firstname != ''
It runs fine in phpMyAdmin but Google Script Editor generates an "Exceeded maximum execution time" error.
It looks like there are 7357 rows (exported from myPhpAdmin). Is there a better way to write the query? Also I am trying to rename the column headers but can only two works, i.e:
GROUP_CONCAT(name SEPARATOR ", ") AS items_purchased
and
CONCAT("£", FORMAT(total,2)) order_value
Any thoughts
QUICK UPDATE: Fri Nov 9 11:54:03 2018
1) As request by #ThisGuyHasTwoThumbs, here is a screenshot of the explain table result
2) I looked into the Best Practices doc mentioned by #bcperth. I tried to rewrite the google sheets script but ran into issues.
Here is the amended script.
function p1MySQLFetchData() {
// Change it as per your database credentials
var conn =
Jdbc.getConnection('jdbc:mysql://[dbHostIp]:3306/[dbName]',
'[dbUsername]', '[dbPassword]');
var stmt = conn.createStatement();
var start = new Date(); // Get script starting time
//change table name as per your database structure
var rs = stmt.executeQuery('[sqlQuery]');
// It sets the limit of the
// maximum nuber of rows in a ResultSet object
// Returns the currently active spreadsheet
var doc = SpreadsheetApp.getActiveSpreadsheet();
var cell = doc.getRange('a1');
var row = 0;
// Mysql table column name count.
var getCount = rs.getMetaData().getColumnCount();
// Create array to hold mysql data
var tempArray = [];
// get row and column count for later
var colCount = getCount;
// ATTEMPT TO GET ROW COUNT 1
//rs.last();
//var rowCount = rs.getRow();
//rs.beforeFirst(); // resets rs cursor
//Logger.log(RowCount);
// DOESN'T WORK! result => ReferenceError: "RowCount" is not
// defined. (line 28, file "Code")
// ATTEMPT TO GET ROW COUNT 2
//var rsCount = stmt.executeQuery('SELECT COUNT(*) AS rowcount FROM
//[sqlQuery]);
// It sets the limit of the maximum number of rows in a ResultSet
// object
//rsCount.next();
//var rowCount = rsCount.getString("rowcount");
//Logger.log(rowCount);
// DOESN'T WORK! result => 0
// Build TempArray using MySQL data
for (var i = 0; i < getCount; i++){
tempArray[0][i] = rs.getMetaData().getColumnName(i+1);
// DOESNT WORK => ERROR
// TypeError: Cannot set property "0.0" of undefined to "order_id".
// (line 39, file "Code")
//Logger.log(rs.getMetaData().getColumnName(i+1));
}
var row = 1;
while (rs.next()) {
for (var col = 0; col < rs.getMetaData().getColumnCount();
col++) {
tempArray[row][col] = rs.getString(col + 1);
//Logger.log(rs.getString(col + 1));
}
row++;
}
// BELOW DOESNT AS I CANT GET A ROW COUNT (SEE ABOVE)
// Fill Spreadsheet from tempArray
//for (var row = 0; row < rowCount; row++) {
//for (var col = 0; col < colCount; col++) {
//cell.offset(row, col).setValue(tempArray[row][col + 1]);
//}
// }
rs.close();
stmt.close();
conn.close();
var end = new Date(); // Get script ending time
Logger.log('Time elapsed: ' + (end.getTime() - start.getTime()));
// To generate script log. To view log click on View -> Logs.
}
But as you can see from the comments, I get loads of errors. Am not sure what to do next.
UPDATE Fri Nov 30 15:26:14 2018
In answer to #Tedinoz comment below.
PhpMyAdmin generates 6862 results and the query took 13.3074 seconds.
When I ran the script in Googles Script Editor, it took around 2 minutes 30 to complete and only pulls 6348 records (92.5%). The records stop after 3rd October 2018.
Regarding your suggestions:
1) I tried running a modified script, setting the INTERVAL to:
1 MONTH => I get no results in Google (it should be 529)
2 MONTH => I get 14 results (should be 1029)
3 MONTH => I get 299 results (should be 1669).
They all took about 4-7 second in myPhpAdmin vs 5 - 20 seconds for Google Script Editor
2) Do you mean exporting a csv from phpMyAdmin and importing to Google Sheets? Well I did that and it works fine.
Another thing I have noticed is that the order_id's in Google Sheets don't match that from phpMyAdmin. Weird.
I'm having an issue with this apps script that's attempting to add data to my Google Cloud database. The problem variables are Open, High, Low, Close; which are all values found by formulas in the 'RAW' sheet. The formulas behind Open, High, Low, Close looks like this:
=round(index(B6:B35,match($A$3,$A$6:$A$35,0))/index(AUD!C:C,match(A3,AUD!A:A,0)),8)
When the query tries to execute the getValue() is returning #N/A, as is getDisplayValue(), which doesn't align with the table parameters.
The problem only occurs when the reference cells include formulas, when I change those cells to integers to test it goes through to the db no problem.
Is there a different way to do this, or stop getValue() returning #N/A?
Many thanks!
OM.
function insert() {
// RAW Variables
var date_ = Utilities.formatDate(SpreadsheetApp.getActiveSpreadsheet().getSheetByName('RAW').getRange('A3').getValue(), "GMT+10", "yyyy-MM-dd");
var open_ = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('RAW').getRange('B3').getValue()
var high_ = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('RAW').getRange('C3').getValue()
var low_ = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('RAW').getRange('D3').getValue()
var close_ = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('RAW').getRange('E3').getValue()
var volume_= SpreadsheetApp.getActiveSpreadsheet().getSheetByName('RAW').getRange('F3').getValue()
// Connection Variables
var connectionName = '.....';
var user = '.....';
var userPwd = '......';
var db = '.....';
var dbUrl = 'jdbc:google:mysql://' + connectionName + '/' + db;
var conn = Jdbc.getCloudSqlConnection(dbUrl, user, userPwd);
var stmt = conn.createStatement()
// Query
var query="insert into test(Date, Open, High, Low, Close, Volume) values('"+date_+"','"+open_+"','"+high_+"','"+low_+"','"+close_+"','"+volume_+"')"
stmt.execute(query)
stmt.close()
conn.close()
}
Update:
Adding iferror() to the begging of the formulas I was able to get the error value through to the table, however that's not an ideal result for me.
The fact that getValue() or getDisplayValues() doesn't return the result of the formula is my biggest concern. What is most strange is that the right most column is also a formula: =index(F6:F35,match($A$3,$A$6:$A$35,0))
The only difference between that formula and the problem ones is a division operator '/'. Any thoughts regarding that?
Outside of testing on the insert query I've also been testing by using the Open, High.. to cell.setValue(), within sheets, and getting the same #N/A result.
| 2018-05-13 | 11278.421244330 | 11620.21125128 | 11118.99605973 | 11554.50481772 | 5866380000 |
| 2018-05-14 | 11576.562811400 | 11799.80070418 | 11118.00969906 | 11581.46548861 | 7364150000 |
| 2018-05-15 | 11657.201395350 | 11832.62472130 | 11324.11133355 | 11396.32950125 | 6705710000 |
| 2018-05-16 | 0.000000000 | 0.00000000 | 0.00000000 | 0.00000000 | 6760220000 |
+------------+-----------------+----------------+----------------+----------------+-------------+
Result from insert query ^
Use IFERROR to eliminate N/A and #DIV/0!
=IFERROR(formula, "value to display if an error occurs")
I can't test yours but I'd say this is what you are looking for:
=IFERROR(round(index(B6:B35,match($A$3,$A$6:$A$35,0))/index(AUD!C:C,match(A3,AUD!A:A,0)),8), 0)
getValue() will now always return 0 or the result.
I had a similar problem when trying to get information from a query with importrange. I think you can't use data from an importrange as a value, though it could be the combination of have both. If your index value in the formula is an importrange data it probably is the reason.
I was trying to make a dynamic formula to paste on my sheets based on the selected column. It kept giving the #N/A while I tried to get information of the column from the importrange. As soon as I went from a match that used the importrange data to a calculated way to determine the column it worked.