App script - Trouble in removing Tables since the 11st - google-apps-script

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.

Related

How to exclude a matching pattern but also include specific values matching the pattern in SQL query?

A SQL query fetches many numbers but excludes the numbers starting with digit 4:
Select Var
from TABLE
Where Var NOT LIKE '4%'
Now I need to include/fetch 3 specific values(in the same query) which also start with 4.
I modified the above query but this doesn't work:
Select Var from Table
where Var NOT LIKE '4%' AND
( Var = '40030' OR Var = '40100' OR Var = '40130' )
I think you are asking for the UNION of Var NOT LIKE '4%' and Var in ('40030', '40100', '40130'). So use an OR condition to accomplish that:
Where (Var in ('40030', '40100', '40130')) or
( Var NOT LIKE '4%')

Script copies row data to another sheet, is only partially working

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.

Prevent MySQL query from timing out in Apps Script

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.

How to read and insert back in the database using linq to sql?

I read a set of data from database first
Insert a new record using same data in same table.
I tried this but:-
using (var db = new
DataContext(ConfigurationManager.ConnectionStrings["DB"].ToString()))
{
var items = from t in db.Table1
where t.ID.Equals(100)
select t;
foreach (var item in items)
{
using (var db1 = new
DataContext(ConfigurationManager.ConnectionStrings["DB"].ToString()))
{
Table1 tab = new Table1
{
FName = item.FName,
LName = item.LName,
Number = item.Number,
};
db1.Table1.InsertAllOnSubmit(tab);
db1.SubmitChanges();
}
}
}
I can't compile it. It throws this error at line 'db1.Table1.InsertAllOnSubmit(tab)':-
'System.Data.Linq.Table.InsertAllOnSubmit(System.Collections.Generic.IEnumerable)'
cannot be inferred from the usage. Try specifying the type arguments
explicitly.
Your code has some flaws.
You seem to read one Table1 (assuming the id is unique) but you are treating it like a collection
Quick try since you anyway add only one table1 at a time: Replace
db1.Table1.InsertAllOnSubmit(tab);
by
db1.Table1.InsertOnSubmit(tab);
If your ID is not unique try:
List<Table1> items = (from t in db.Table1
where t.ID.Equals(100)
select t).ToList();
The rest of the code can stay the same (but still replace the InsertAllOnSubmit)
Update
You can simplify bigtime:
using (var db = new
DataContext(ConfigurationManager.ConnectionStrings["DB"].ToString()))
{
Table1 thisTable = (from t in db.Table1
where t.ID. == 100
select t).SingleOrDefault();
if ( thisTable != null)
{
Table1 tab = new Table1 ()
{
FName = item.FName,
LName = item.LName,
Number = item.Number, };
db.Table1.InsertOnsubmit(tab)
db.SubmitChanges();
}
}
}
if you are 100% sure your id will always match use .Single() instead of .SingleOrDefault(). Single will throw an exception if no result matches. SingleOrDefault returns NULL in this case.

too many fields to specify in result set of join

So similar questions have been asked with not much of an answer....
I have a Stats Table related to a Branch table. The Stats records contain pc stats of a particular bank branch.
Branch
+Code
+Name
+Area
...
Stats
+BranchCode
+IP
+UpSpeed
+DownSpeed
...
Here is my linq query...
var stats = from st in store.Stats
join b in store.Branches on st.BranchCode equals b.Brcd
select new
{
st.ID,st.IP,st.Name,b.Brcd,b.Branch_Name..............
};
The issue is st and b have a LOT of fields, for now I guess I will type them all... but isn't there a solution to this? *Prevent the typing of all fields... something like a * wildcard?
Did try intersect however the types need to be the same!
Thanks
Gideon
1
var stats =
from st in store.Stats
join b in store.Branches on st.BranchCode equals b.Brcd
select new
{
Stats = st,
Branch = b
};
Creates anonymous instances with one Stats and one Branch.
2
var stats =
from b in store.Branches
join st in store.Stats
on b.Brcd equals st.BranchCode
into branchstats
select new
{
Branch = b
Stats = branchstats
};
Creates anonymous instances with one Branch and its Stats.
3
var stats =
from b in store.Branches
select new
{
Branch = b
Stats = b.Stats
};
Same as 2, If there's an association between the two types in the designer, then there's a relational property generated on each type.
4
DataLoadOptions dlo = new DataLoadOptions()
dlo.LoadWith<Branch>(b => b.Stats);
store.LoadOptions = dlo;
List<Branch> branches = store.Branches.ToList();
Here, DataLoadOptions are specified that automatically populate the Stats property when any Branch is loaded.