Last row writes twice - loops

I had a broken code which I have managed to get working (The original question is here https://stackoverflow.com/questions/29127005/multiple-spreadsheet-rows-from-multiple-forms), but the loop writes the last line twice and my coding skills are not good enough for me to work out why...yet!
Can anyone shed any light on what I have/haven't included?
function InsertDataInSheet(e) //Function to insert data into spreadsheet on clicking submit
{
var app = UiApp.getActiveApplication();
//get number of rows to input
var num = parseInt(e.parameter.table_tag);
var num = num+1;
//set increment step through
for (var i = 1; i < num ; i++ ) {
//Declare varialbe fields to collect data from
var user = Session.getActiveUser().getEmail();
var date = e.parameter['DateBox'+i];
var location = e.parameter['LocationListBox'+i];
var source = e.parameter['SourceListBox'+i];
var reporter = e.parameter['ReporterTextBox'+i];
var priority = e.parameter['PriorityListBox'+i];
var hazard = e.parameter['HazardListBox'+i];
var details = e.parameter['DetailsTextBox'+i];
var description = e.parameter['DescriptionTextBox'+i];
var timeStamp = new Date();
//Decide date that this needs to be closed by
if (priority === '02 - WITHIN 24-48 HOURS') {
var dateTemp = new Date(date);
dateTemp.setDate(dateTemp.getDate()+2);
var actiondate = dateTemp;
}
if (priority === '03 - WITHIN 1 WEEK') {
var dateTemp = new Date(date);
dateTemp.setDate(dateTemp.getDate()+7);
var actiondate = dateTemp;
}
//establish email addresses
//Declare correct range to obtain values
var LocationSheet = SpreadsheetApp.openById(itemSpreadsheetKey).getSheetByName("LocationCodes")
//Start with central maintenance department
var email00 = LocationSheet.getRange(33,5).getValue()
//followed by other emails as they appear
var email01 = LocationSheet.getRange(3,5).getValue();
var email02 = LocationSheet.getRange(4,5).getValue();
//declare the correct Depots to check
var LocationSheet = SpreadsheetApp.openById(itemSpreadsheetKey).getSheetByName("LocationCodes");
var depot01 = LocationSheet.getRange(3,4).getValue();
var depot02 = LocationSheet.getRange(4,4).getValue();
//if source is recorded as '08 - Maitenance Request System', the recipient is maintenance deparment
if (source === "08 - Maintenance Request System"){
var recipient = email00;
//or depots as listed
} else if(location === depot01){
var recipient = email01;
} else if(location === depot02){
var recipient = email02; }
else {
//and send an email to the error catch all if no code supplied
var recipient = email00; //change as necessary
}
var sheet = SpreadsheetApp.openById(itemSpreadsheetKey).getSheetByName('LOG');
var lastRow = sheet.getLastRow();
var lrp1 = lastRow+1
var targetRange = sheet.getRange(lastRow+1, 1, 1, 12).setValues([[timeStamp,date,source,location,reporter,user,hazard,details,description,priority,recipient,actiondate]]);
//Notification Page
app = UiApp.getActiveApplication().remove(0);
app.createVerticalPanel()
.setId('info')
.setVisible(true)
.setStyleAttribute('left', 10)
.setStyleAttribute('top', 10)
.setStyleAttribute('zIndex', '1')
.setStyleAttribute('position', 'fixed')
.setStyleAttribute('background', 'white')
.setHeight('400px')
.setStyleAttribute('text-align', 'center')
.setBorderWidth(1)
.setWidth('500px');
app.add(app.createLabel('Your submission has been added to the database & the Site Coordinator will be emailed with notification.'));
// app.add(app.createLabel('The details you entered were recorded as:'));
// app.add(app.createLabel('Username: [' +user+ '] Timestamp: [' +timeStamp+ '] Reporter: [' +reporter+ ']'));
// app.add(app.createLabel('Location: [' +location+ '] Hazard: [' +hazard+ '] Source: [' +source+ ']'));
// app.add(app.createLabel('You listed the priority as: [' +priority+ '], please be aware this may not be the same priority given by the Site Coordinator responsible.'));
app.add(app.createLabel('Please refresh this page to submit more entries'));
return app.close();
}
var sheet = SpreadsheetApp.openById(itemSpreadsheetKey).getSheetByName("LOG");
var lastRow = sheet.getLastRow();
var lrp1 = lastRow+1
//Amend [getRange(lastRow+1, 1, 1, **)] integer to reflet number of headers being written if more added
var targetRange = sheet.getRange(lastRow+1, 1, 1, 12).setValues([[timeStamp,date,source,location,reporter,user,hazard,details,description,priority,recipient,actiondate]]);
var Body = 'A new [' +source+ '] log entry has been recorded at [' +location+ '], listed as [' + hazard+ ']. This form was submitted by [' +user+ '] with the timestamp [' +timeStamp+ '].'
}

The reason why it is adding last row twice is that because the following code is repeated after the loop:
var sheet = SpreadsheetApp.openById(itemSpreadsheetKey).getSheetByName("LOG");
var lastRow = sheet.getLastRow();
var lrp1 = lastRow+1
//Amend [getRange(lastRow+1, 1, 1, **)] integer to reflet number of headers being written if more added
var targetRange = sheet.getRange(lastRow+1, 1, 1, 12).setValues([[timeStamp,date,source,location,reporter,user,hazard,details,description,priority,recipient,actiondate]]);
var Body = 'A new [' +source+ '] log entry has been recorded at [' +location+ '], listed as [' + hazard+ ']. This form was submitted by [' +user+ '] with the timestamp [' +timeStamp+ '].'
Hope that helps!

Thanks KRR, I sorted it with that and the moving of one of the "}" from after the notification page to just before it. The corrected code is:
var sheet = SpreadsheetApp.openById(itemSpreadsheetKey).getSheetByName('LOG');
var lastRow = sheet.getLastRow();
var lrp1 = lastRow+1
var targetRange = sheet.getRange(lastRow+1, 1, 1, 12).setValues([[timeStamp,date,source,location,reporter,user,hazard,details,description,priority,recipient,actiondate]]);
}
///// TRAIL NOTIFICATION PAGE FROM WITHIN SYSTEM FROM HERE /////
app = UiApp.getActiveApplication().remove(0);
app.createVerticalPanel()
.setId('info')
.setVisible(true)
.setStyleAttribute('left', 10)
.setStyleAttribute('top', 10)
.setStyleAttribute('zIndex', '1')
.setStyleAttribute('position', 'fixed')
.setStyleAttribute('background', 'white')
.setHeight('400px')
.setStyleAttribute('text-align', 'center')
.setBorderWidth(1)
.setWidth('500px');
app.add(app.createLabel('Your submission has been added to the database & the Site Coordinator will be emailed with notification.'));
// app.add(app.createLabel('The details you entered were recorded as:'));
// app.add(app.createLabel('Username: [' +user+ '] Timestamp: [' +timeStamp+ '] Reporter: [' +reporter+ ']'));
// app.add(app.createLabel('Location: [' +location+ '] Hazard: [' +hazard+ '] Source: [' +source+ ']'));
// app.add(app.createLabel('You listed the priority as: [' +priority+ '], please be aware this may not be the same priority given by the Site Coordinator responsible.'));
app.add(app.createLabel('Please refresh this page to submit more entries'));
return app.close();
}

Related

Snowflake stored procedure - while loop only iterates over first row in the table

create or replace procedure "CS_DEV"."META".SP_DATA_RETENTION("Trgt_DB" VARCHAR, "Trgt_Schema" VARCHAR, "Trgt_Stage" VARCHAR(20))
returns string
language JavaScript
EXECUTE AS CALLER
as
$$
var select_stmt = `SELECT * FROM ` + Trgt_DB + `.META.PREPROCESS_META`;
var select_stmt_sql = { sqlText: select_stmt };
var select_stmt_create = snowflake.createStatement(select_stmt_sql);
var select_stmt_exec = select_stmt_create.execute();`
while (select_stmt_exec.next()) {
var TGT_SCHEMA_NAME = select_stmt_exec.getColumnValue(5);
var TGT_TABLE_NAME = select_stmt_exec.getColumnValue(6);
var retentt = select_stmt_exec.getColumnValue(13);
var retentp = select_stmt_exec.getColumnValue(12);
var remove_data_tbl = `delete from ` +TGT_SCHEMA_NAME+ `.` +TGT_TABLE_NAME+ ` A USING META.PREPROCESS_META B where A.SYS_DATE <= DATEADD('`+retentt+`', -`+retentp+`, current_date()) AND B.RETENTION_TYPE = '`+retentt+`' AND B.RETENTION_PERIOD = `+retentp+ ` AND B.TGT_SCHEMA_NAME = '`+TGT_SCHEMA_NAME+ `' AND B.TGT_TABLE_NAME = '` +TGT_TABLE_NAME+`'`;
var remove_data_tbl_sql = {sqlText: remove_data_tbl };
var remove_data_tbl_create = snowflake.createStatement(remove_data_tbl_sql);
var remove_details_exec = remove_data_tbl_create.execute();}
Running the first statement produces the table above and then TGT_SCHEMA_NAME, TGT_TABLE_NAME, RETENTION_TYPE, and RETENTION_PERIOD values are taken and iterated through, however the procedure will only iterate over the first row DIM_AIRLINES.
Here's a slightly modified version. Can you run this and see its output? If it fails, look in the query history tab to see what SQL the procedure attempted to run. Then you can make adjustments as required. If you need more help post the error(s) you're getting when running the procedure and/or the SQL errors in the query history tab.
create or replace procedure "CS_DEV"."META".SP_DATA_RETENTION("Trgt_DB" VARCHAR, "Trgt_Schema" VARCHAR, "Trgt_Stage" VARCHAR(20))
returns string
language JavaScript
EXECUTE AS CALLER
as
$$
"option strict"
var sql = `SELECT * FROM ${Trgt_DB}.META.PREPROCESS_META`;
var rs = exec(sql);
var tgtSchemaName;
var tgtTableName;
var retentt;
var retentp;
var remove_data_tbl;
while (rs.next()) {
tgtSchemaName = select_stmt_exec.getColumnValue(5);
tgtTableName = select_stmt_exec.getColumnValue(6);
retentt = select_stmt_exec.getColumnValue(13);
retentp = select_stmt_exec.getColumnValue(12);
remove_data_tbl = `delete from ${tgtSchemaName}.${tgtTableName} A USING META.PREPROCESS_META B
where A.SYS_DATE <= DATEADD('$retentt', -${retentp}, current_date()) AND B.RETENTION_TYPE = '${retentt}' AND B.RETENTION_PERIOD = ${retentp} AND B.TGT_SCHEMA_NAME = '${tgtSchemaName}' AND B.TGT_TABLE_NAME = '${tgtTableName}'`;
exec(remove_data_tbl);
}
// ---- End main function. Start of helper functions.
function exec(sql){
cmd = {sqlText: sql};
stmt = snowflake.createStatement(cmd);
var rs;
rs = stmt.execute();
return rs;
}
$$;

proc or function that will loop over each database in snowflake and list tables with empty rows

Can someone help find these zero row tables?
CREATE OR REPLACE PROCEDURE checkrows()
RETURNS VARIANT
LANGUAGE JAVASCRIPT
AS
$
function ExecuteNonQuery(querystring) {
var out = '';
cmd1 = {sqlText: select * from information_schema.tables where rows_count = 0;};
stmt = snowflake.createStatement(cmd1);
var rs;
try{
rs = stmt.execute();
rs.next();
out = "SUCCESS: " + rs.getColumnValue(0);
}
catch(err) {
throw "ERROR: " + err.message.replace(/\n/g, " ");
}enter code here
return out;
}
$$;
If you have a use case that it's okay to get row counts that are several minutes older than the last change (generally 15-90 minutes but up to 3 hours), you can simply run this:
select * from "SNOWFLAKE"."ACCOUNT_USAGE"."TABLES"
where TABLE_TYPE = 'BASE TABLE' and DELETED is null and ROW_COUNT = 0;
Edit: Since this needs to be automated, this SP will return a variant array with objects containing the db, schema, and table name of all tables with zero rows.
create or replace procedure FIND_EMPTY_TABLES(DATABASE_PATTERN string) -- Use .* for all databases in account. It will skip SNOWFLAKE and SNOWFLAKE_SAMPLE_DATA
returns variant
language javascript
execute as owner
as
$$
class Account {constructor(databases){this.databases = databases;}}
class Database {constructor(name) {this.name = name;}}
class Query{constructor(statement){this.statement = statement;}}
var account = getDatabasesInAccount(DATABASE_PATTERN);
var out = [];
for (var i = 0; i < account.databases.length; i++) {
out = out.concat(rsToJSON(getQuery(
`select TABLE_NAME, TABLE_CATALOG, TABLE_SCHEMA, TABLE_OWNER
from ${account.databases[i].name}.INFORMATION_SCHEMA.TABLES
where TABLE_TYPE = 'BASE TABLE' and ROW_COUNT = 0`)));
}
return out;
//------
function getQuery(sql){
cmd1 = {sqlText: sql};
var query = new Query(snowflake.createStatement(cmd1));
query.resultSet = query.statement.execute();
return query;
}
function executeSingleValueQuery(columnName, queryString) {
cmd = {sqlText: queryString};
stmt = snowflake.createStatement(cmd);
var rs;
rs = stmt.execute();
rs.next();
return rs.getColumnValue(columnName);
}
function getDatabasesInAccount(databasePattern){
const SYSTEM_DB_NAMES = ["SNOWFLAKE", "SNOWFLAKE_SAMPLE_DATA"];
var db = executeSingleValueQuery("name", "show databases");
var i = 0;
var dbRS = getResultSet(`select DATABASE_NAME from "${db}".INFORMATION_SCHEMA.DATABASES where rlike (DATABASE_NAME, '${databasePattern}');`);
var databases = [];
var db;
while (dbRS.next()){
db = new Database(dbRS.getColumnValue("DATABASE_NAME"));
if (!SYSTEM_DB_NAMES.includes(db)) {
databases.push(db);
}
}
return new Account(databases);
}
function getResultSet(sql){
let cmd = {sqlText: sql};
let stmt = snowflake.createStatement(cmd);
let rs = stmt.execute();
return rs;
}
function rsToJSON(query) {
var i;
var row = {};
var table = [];
while (query.resultSet.next()) {
for(col = 1; col <= query.statement.getColumnCount(); col++) {
row[query.statement.getColumnName(col)] = query.resultSet.getColumnValue(col);
}
table.push(row);
}
return table;
}
$$;
call FIND_EMPTY_TABLES('.*'); -- .* is the RegExp pattern that tell it to check all databases except built-in ones.
Dirty and quick option adding to gregs excellent answer ... obviously if you like the results add 'create or replace zero_row_count_base_tables as ...' .... set it to re-create the view maybe weekly/daily then run the view when you want.
SELECT
' SELECT TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME from UTIL_DB.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = \'BASE TABLE\' AND ROW_COUNT > 0 '
UNION
SELECT concat( 'UNION SELECT TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME
FROM ', DATABASES.DATABASE_NAME,'.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = \'BASE TABLE\' AND ROW_COUNT > 0 ')
FROM UTIL_DB.INFORMATION_SCHEMA.DATABASES

loop through sheet for unmarked value to update Google contacts

I've got a working script that grabs the last row of a Google sheet and pushes the info into Google contacts.
var ss = SpreadsheetApp.getActiveSheet(); //var emailRow = ss.getRange('F2:F').getValues();
var emailRowNum = ss.getLastRow(); //var emailRowNum = emailRow.filter(String).length + 1;
function email() {
var emailNew = ss.getRange(emailRowNum,6).getValue(); //var emailNew = ss.getRange("F"+emailRowNum).getValues();
return emailNew;}
function givenName() {
var fname = ss.getRange(emailRowNum,4).getValue();
return fname;}
function lastName() {
var lname = ss.getRange(emailRowNum,5).getValue();
return lname;}
function loc() {
var street = ss.getRange(emailRowNum,8).getValue();
var city = ss.getRange(emailRowNum,9).getValue();
return street + " " + city;}
function phone() {
var phone = ss.getRange(emailRowNum,7).getValue();
return phone;}
function notes() {
var date = ss.getRange(emailRowNum,1).getValue();
var work = ss.getRange(emailRowNum,2).getValue();
var photo = ss.getRange(emailRowNum,3).getValue();
var site = ss.getRange(emailRowNum,12).getValue();
var find = ss.getRange(emailRowNum,10).getValue();
var referrer = ss.getRange(emailRowNum,11).getValue();
return (date + "\n\n" + work + "\n\n" + photo + "\n\n" + site + "\n\n" + find + " " + referrer + "\n\n-- eom --\n\n");}
function create() {
var fname = givenName();
var lname = lastName();
var contact = ContactsApp.createContact(fname, lname, email());
var group = ContactsApp.getContactGroup('emf');
group.addContact(contact);
var contacts = ContactsApp.getContactsByName(fname + ' ' + lname);
var setaddress = contacts[0].addAddress(ContactsApp.Field.HOME_ADDRESS,loc());
var setphone = contacts[0].addPhone(ContactsApp.Field.MAIN_PHONE,phone());
for (var i in contacts) {
contacts[i].setNotes(notes());
}
}
I'd like to modify it so that instead of grabbing the last row, it checks a column for a (not) value. If value is not found, then update Google contacts with that row's information.
Currently, I'm getting a 'Range not found' error ...
function info(){
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getRange("N1:N").getValues();
for(var n=0;n<data.length;n++){
if(data[n-1] != 'done'){
var email = ss.getRange("F"+n).getValue(); // Range not found error
var fname = ss.getRange("D"+n).getValue();
var lname = ss.getRange("E"+n).getValue();
var city = ss.getRange("I"+n).getValue();
var street = ss.getRange("H"+n).getValue();
var phone = ss.getRange("G"+n).getValue();
var date = ss.getRange("A"+n).getValue();
var work = ss.getRange("B"+n).getValue();
var photo = ss.getRange("C"+n).getValue();
var site = ss.getRange("L"+n).getValue();
var find = ss.getRange("J"+n).getValue();
var referrer = ss.getRange("K"+n).getValue();
var contact = ContactsApp.createContact(fname, lname, email);
var group = ContactsApp.getContactGroup('emf');
group.addContact(contact);
var contacts = ContactsApp.getContactsByName(fname + ' ' + lname);
var setaddress = contacts[0].addAddress(ContactsApp.Field.HOME_ADDRESS,street + " " + city);
var setphone = contacts[0].addPhone(ContactsApp.Field.MAIN_PHONE,phone);
for (var i in contacts) {
contacts[i].setNotes(date + "\n\n" + work + "\n\n" + photo + "\n\n" + site + "\n\n" + find + " " + referrer + "\n\n-- eom --\n\n");}
}
}
}
1 is the first row using A1Notation with getRange(). The first iteration is trying to getValue() of F0. Changing the n to start at 1 and n <= data.length should get the ranges you are looking for.
...
for(var n=1;n<=data.length;n++){
if(data[n-1] == 'done'){
var email = ss.getRange("F"+n).getValue(); // Range not found error
...
edit: One thing to note the var data = ss.getRange("N1:N").getValues(); range is going to loop over all 1000 default rows. This may not be ideal if your data set is significantly smaller than 1000 rows.

Angularjstable example

hai guys i got data from restfull web service to angular function i need to place this data in the form table but i am not getting the code so pls help me my code is. I need to show in table form what i get in json pls suggest me
<script type="text/javascript">
function ContactController($scope,$http) {
// $scope.contacts = ["hi#email.com", "hello#email.com"];
$scope.add = function() {
$http.get('http://localhost:8080/ProjectManagement/REST/GetProject/Details').success(function(data, status, headers, config,response){
var json = JSON.stringify(data);
var getresponseText = JSON.parse(json);
var prjdetails=getresponseText.responseText;
var fields = getresponseText.split("|");
$scope.people = [];
var projectid = fields[0];
var projectname = fields[1];
var claintid = fields[2];
var projectstatus = fields[3];
var prjstartdate = fields[4];
var prjenddate = fields[5];
var lastmodified = fields[6];
var prjpinurl = fields[7];
claim = '';
claim = '{ "records":[{';
claim += '"projectid": "'+ projectid+ '", ';
claim += '"projectname": "'+ projectname+ '", ';
claim += '"claintid": "'+ claintid+ '", ';
claim += '"projectstatus": "'+ projectstatus + '", ';
claim += '"prjstartdate": "'+prjstartdate+ '", ';
claim += '"prjenddate": "'+ prjenddate + '", ';
claim += '"lastmodified": "'+ lastmodified + '", ';
claim += '"prjpinurl": "'+ prjpinurl + '", ';
claim += '}]}';
}).error(function(data, status, headers, config,response) {
});
}
}
</script>
If you get json returned from the server, do not call JSON.stringify since it is already "stringified" when sent from the server.
It is not possible to help you further without seeing the actual response from the server.

Change Google App Script to select specific sheet and clear it before continuing script

I've worked out a script to gather data from a remote MS SQL db and populate a Google Sheet. I need some help further refining the code to select a specific sheet and clear the sheet before continuing the script so that each time the script runs the sheet has the latest data from the db table.
Here is the script.
function database_connection() {
var conn = Jdbc.getConnection("jdbc:sqlserver://x.x.x.x:1433;" + "databaseName=mydbname;user=mydbusername;password=mypassword;");
var stmt = conn.createStatement();
stmt.setMaxRows(500);
var start = new Date();
var rs = stmt.executeQuery('select * from table_name');
var doc = SpreadsheetApp.getActiveSpreadsheet();
var cell = doc.getRange('a1');
var row = 0;
while (rs.next()) {
for (var col = 0; col < rs.getMetaData().getColumnCount(); col++) {
cell.offset(row, col).setValue(rs.getString(col + 1));
}
row++;
}
rs.close();
stmt.close();
conn.close();
var end = new Date();
Logger.log('Time elapsed: ' + (end.getTime() - start.getTime()));
}
To select a sheet you can use getSheetByName or getSheets as per your requirement.
To clear the all the cells in a sheet, use the clear method of class Range.
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheet = doc.getSheetByName("sheetName");
sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).clear()
Googling will definitely help...
Edit
getDataRange can also be used to clear all the ranges (see below)
This is how you can use bulk insert
function database_connection() {
var conn = Jdbc.getConnection("jdbc:sqlserver://x.x.x.x:1433;" + "databaseName=mydbname;user=mydbusername;password=mypassword;");
var stmt = conn.createStatement();
stmt.setMaxRows(500);
var start = new Date();
var rs = stmt.executeQuery('select * from table_name');
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheet = doc.getSheetByname("sheetName")
sheet.getDataRange().clear();
var data = [], rowData;
var numCols = rs.getMetaData().getColumnCount(); // <- not sure about this, basically i want to capture number of columns
while (rs.next()) {
rowData = [];
for (var col = 0; col < numCols; col++) {
rowData.push(rs.getString(col + 1));
}
data.push(rowData);
}
sheet.getRange(1, 1, data.length, numCols).setValues(data); // <- single operation to insert
rs.close();
stmt.close();
conn.close();
var end = new Date();
Logger.log('Time elapsed: ' + (end.getTime() - start.getTime()));
}

Resources