I have data in "Raw data" sheet 45000 rows. So I created a function that whenever I run this function will group my data to pivot table may be in 500 rows and turn to new format but totally take more than 30 minutes.
function sumData() {
var spreadsheet = SpreadsheetApp.getActive();
var ss = SpreadsheetApp.getActive().getSheetByName('Raw data');
var sourceData = spreadsheet.getRange('A1:I100000');
var pivotTable = spreadsheet.getRange('A1').createPivotTable(sourceData);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Pivot table'), true);
sourceData = spreadsheet.getRange('\'Raw data\'!A1:I100000');
pivotTable = spreadsheet.getRange('A1').createPivotTable(sourceData);
var pivotValue = pivotTable.addPivotValue(3, SpreadsheetApp.PivotTableSummarizeFunction.COUNTA);
pivotGroup = pivotTable.addRowGroup(6);
pivotGroup.showTotals(false).showRepeatedLabels();
pivotGroup = pivotTable.addRowGroup(2);
pivotGroup.showTotals(false).showRepeatedLabels();
pivotGroup = pivotTable.addRowGroup(3);
pivotGroup.showTotals(false);
var ss1 = SpreadsheetApp.getActive().getSheetByName('Pivot table');
var ss2 = SpreadsheetApp.getActive().getSheetByName('Summary data');
ss2.getRange('A:D').activate();
ss2.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
ss2.setFrozenRows(1);
var value = [["Shop order", "Part number", "count Workstation", "Workstation"]];
var range = ss2.getRange("A1:D1");
range.setValues(value);
var data = ss1.getRange(1, 1).getValue()
for(var i = 1, j = 1; i < ss1.getLastRow()+1; i++) {
var normalCase = true
if(i!=1) {
if(ss1.getRange(i, 1).getValue() == data) {
normalCase = false
ss2.getRange(j, 3).setValue(ss1.getRange(i, 4).getValue()+ss2.getRange(j, 3).getValue()) // for update count workstation
ss2.getRange(j, 4).setValue(ss1.getRange(i, 3).getValue()+ " = " +ss1.getRange(i, 4).getValue()+ ", " +ss2.getRange(j, 4).getValue()) // for update value
} else {
j++}}
if(normalCase) {
ss2.getRange(j, 1).setValue(ss1.getRange(i, 1).getValue())
ss2.getRange(j, 2).setValue(ss1.getRange(i, 2).getValue())
ss2.getRange(j, 3).setValue(ss1.getRange(i, 4).getValue())
ss2.getRange(j, 4).setValue(ss1.getRange(i, 3).getValue()+ " = " +ss1.getRange(i, 4).getValue())}
data = ss1.getRange(i, 1).getValue()}
ss2.deleteRow(2);
var ui = SpreadsheetApp.getUi();
ui.alert('Summarize complete.');
};
Is there any way to make my code run faster or maybe just a way to make the script run in 10-15 minutes?
Related
I'm looking to create a spreadsheet where it logs data and the changes you make on it.
For example in sheet, I used a Google Script to do it but instead of only logging in a particular row when you change the data on Sheet1, it copies all the data you changed since the beginning on Sheet 2. I only want to log a particular row each time I make a change.
Here's my code
* Retrieves all the rows in the active spreadsheet that contain Yes
* in the Include column and copies them to the Report sheet.
*/
function myFunction() {
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = sSheet.getSheetByName("Sheet1");
var tarSheet = sSheet.getSheetByName("Sheet2");
var lastRow = srcSheet.getLastRow();
for (var i = 2; i <= lastRow; i++) {
var cell = srcSheet.getRange("B" + i);
var val = cell.getValue();
if (val == 'Yes') {
var srcRange = srcSheet.getRange("A" + i + ":D" + i);
var tarRow = tarSheet.getLastRow();
tarSheet.insertRowAfter(tarRow);
var tarRange = tarSheet.getRange("A" + (tarRow+1) + ":D" + (tarRow+1));
srcRange.copyTo(tarRange);
}
}
};
Can anyone please help?
Use onEdit(e)
function onEdit(e) {
var srcSheet = e.source.getActiveSheet();
if (srcSheet.getSheetName() !== 'Sheet1') { return; }
var row = e.range.rowStart;
var cols = 4;
var srcRange = srcSheet.getRange(row, 1, 1, cols);
var values = srcRange.getValues()[0];
if (values[1] == 'Yes') {
var tarSheet = e.source.getSheetByName('Sheet2');
tarSheet.appendRow(values);
}
}
I am using the script made by Mike Seekwell [Link] for connecting a MySQL database to a Sheet, and it works.
My problem is that I need it to run always from the first cell of the first sheet, while actually it can run from every active cell of every active sheet.
How can I modify this thing?
Here is the script:
/**
* #OnlyCurrentDoc
*/
var MAXROWS = 1000
var SEEKWELL_J_SHORT_DATES = { day: "yyyy-MM-dd", month: "yyyy-MM", year: "yyyy", dayNum: "dd", monthNum: "MM", yearNum: "yyyy", week: "W" }
var SEEKWELL_J_TIMEZONE = "UTC"
var HOST = '//host'
var PORT = '//port'
var USERNAME = '//username'
var PASSWORD = '//password'
var DATABASE = '/database'
var DB_TYPE = 'mysql'
function goToSheet(sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName(sheetName));
};
function runSql(query, options) {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheet = doc.getActiveSheet();
var sheetName = sheet.getName();
var cell = doc.getActiveSheet().getActiveCell();
var activeCellRow = cell.getRow();
var activeCellCol = cell.getColumn();
try {
var fullConnectionString = 'jdbc:' + DB_TYPE + '://' + HOST + ':' + PORT
var conn = Jdbc.getConnection(fullConnectionString, USERNAME, PASSWORD);
console.log('query :', query)
var stmt = conn.createStatement();
stmt.execute('USE ' + DATABASE);
var start = new Date();
var stmt = conn.createStatement();
stmt.setMaxRows(MAXROWS);
var rs = stmt.executeQuery(query);
} catch (e) {
console.log(e, e.lineNumber);
Browser.msgBox(e);
return false
}
var results = [];
cols = rs.getMetaData();
console.log("cols", cols)
var colNames = [];
var colTypes = {};
for (i = 1; i <= cols.getColumnCount(); i++) {
var colName = cols.getColumnLabel(i)
colTypes[colName] = { type: cols.getColumnTypeName(i), loc: i }
colNames.push(colName);
}
var rowCount = 1;
results.push(colNames);
while (rs.next()) {
curRow = rs.getMetaData();
rowData = [];
for (i = 1; i <= curRow.getColumnCount(); i++) {
rowData.push(rs.getString(i));
}
results.push(rowData);
rowCount++;
}
rs.close();
stmt.close();
conn.close();
console.log('results', results)
var colCount = results[0].length
var rowCount = results.length
var comment = "Updated on: " + (new Date()) + "\n" + "Query:\n" + query
if (options.omitColumnNames) {
results = results.slice(1)
rowCount -= 1
}
if (options.clearColumns && sheet.getLastRow() > 0) {
var startCellRange = sheet.getRange(startCell)
sheet.getRange(startCellRange.getRow(), startCellRange.getColumn(), sheet.getLastRow(), colCount).clearContent();
}
if (options.clearSheet) {
var startCellRange = sheet.getRange(startCell)
sheet.clear({ contentsOnly: true });
}
sheet.getRange(activeCellRow, activeCellCol, rowCount, colCount).clearContent();
sheet.getRange(activeCellRow, activeCellCol, rowCount, colCount).setValues(results);
var cell = sheet.getRange(activeCellRow, activeCellCol)
cell.clearNote()
cell.setNote(comment);
sheet.setActiveRange(sheet.getRange(activeCellRow + rowCount + 1, activeCellCol))
console.log('query success!, rows = ', rowCount - 1)
}
function runSqlFromSheet() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sql = doc.getRange('query!a2').getDisplayValue();
var options = {}
Logger.log('sql;', sql)
runSql(sql, options)
}
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('SeekWell Blog')
.addItem('Run SQL', 'runSqlFromSheet')
.addToUi();
}
function launch() {
var html = HtmlService.createHtmlOutputFromFile('sidebar')
.setTitle('SeekWell');
SpreadsheetApp.getUi()
.showSidebar(html);
}
I solved the problem. Not in the most elegant way, but it is a solution...
In order to run the script always on the same sheet, I substitute two variables.
The first variable to substitute is the following one:
var sheet = doc.getActiveSheet();
With this one (so it is always the first tab)
var sheet = doc.getSheets()[0];
Then the following one:
var cell = doc.getActiveSheet().getActiveCell();
With this one (so it is possible to define from which cell the script has to start, in this example from A1)
var cell = sheet.getRange('A1');
I'm relatively new to coding, so thanks in advance for any assistance here.
I have a script that runs two functions on the same sheet.
Button2 contains a function (email_button2) that runs a SQL query and pulls info into columns A to D
Button1 also contains a function (email_button1) that runs a separate query and I want to pull this info in columns G to AA (21 columns)
Right now, when I click Button1, I get the following error: Incorrect range width, was 1 but should be 21
Any idea what I should change or add to my script?
function data_button() {
// Logger.log(e)
var thisDoc = SpreadsheetApp.getActiveSpreadsheet();
var helpers = thisDoc.getSheetByName("helper");
query =
helpers.getRange(3,2).getValue().split(String.fromCharCode(13)).join(" ").split(String.fromCharCode(10)).join(" ")
// lastrow = helpers.getRange("lastrow").getValue()
do_query(query,"data")
}
function email_button1() {
// Logger.log(e)
var thisDoc = SpreadsheetApp.getActiveSpreadsheet();
var helpers = thisDoc.getSheetByName("helper");
query =
helpers.getRange(4,2).getValue().split(String.fromCharCode(13)).join("
").split(String.fromCharCode(10)).join(" ")
// lastrow = helpers.getRange("lastrow").getValue()
do_query(query,"emails",11,7)
}
function email_button2() {
// Logger.log(e)
var thisDoc = SpreadsheetApp.getActiveSpreadsheet();
var helpers = thisDoc.getSheetByName("helper");
query =
helpers.getRange(5,2).getValue().split(String.fromCharCode(13)).join("
").split(String.fromCharCode(10)).join(" ")
// lastrow = helpers.getRange("lastrow").getValue()
do_query(query,"emails",11,1)
}
function do_query(query,sheetname,startRow,startCol){
//List of lists?
var url= "xxxxxxxxxxxxxx"
var q = {"query":query}
var options = {
'method' : 'post',
'payload' : q,
'muteHttpExceptions': true
};
var response = UrlFetchApp.fetch(url, options); // get feed
var response2 = response.getContentText()
var rows = response2.split(";;;")
var columnCount = rows[0].length
var data = [];
for(var i = 0; i < rows.length; i++){
var row = rows[i].split('|||');
data.push(row);
}
Logger.log(data)
var a = data[1]
var thisDoc = SpreadsheetApp.getActiveSpreadsheet();
var sheet2 = thisDoc.getSheetByName(sheetname);
sheet2.getRange(startRow,startCol,200,4).clear()
sheet2.getRange(startRow,startCol, data.length,
data[0].length).setValues(data);
//this line above designates column headers
//sheet2.getRange(12, 1, data[1].length, data[1] .
[0].length).setValues(data[1]);
//Logger.log(data[0].length)
//Logger.log(data[0][0].length)
//Logger.log(data[0])
// thisDoc.getSheetByName("helper").getRange("lastrow").setValue(data.length)
}
I'm new to GAS. I'm trying to accomplish four tasks in a single spreadsheet with three separate sheets to relate to.
I want to copy data from the 'rawData sheet', set it in an array, rearrange the array, and set the values in the 'destination sheet'. And keep it active for new submissions (i.e. getLastRow/appendRow).
In 'destination sheet' I want to color code based on status.
Create a button in 'destination sheet' to mark row(case) complete and move from 'destination' to the 'complete sheet'.
And add onEdit triggers for each.
Your input is greatly appreciated.
Thanks.
function colorCode() {
var range = outerArray;
Logger.log(range);
var row = dBoard.getRange(dBoard.getLastRow(),1,1,dBoard.getLastColumn());
var submitter = range[3];
var status = range[11];
Logger.log(submitter);
Logger.log(status);
//var column = range.getColumn();
//var row = range.getRow();
if (status === "Approved"){
var rowToColor = row.offset(0,0,1,13);
rowToColor.setBackground("#6bb2ff");
}
else if (status === "Requester"){
var rowToColor = row.offset(0,0,1,13);
rowToColor.setBackground("#ffe16b");
}
else if (range === 12 && range > 1 && status === "Denied"){
var rowToColor = row.offset(0,0,1,13);
rowToColor.setBackground("#f9441b");
}
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source1 = ss.getSheetByName("Copy of rawData");
var dBoard = ss.getSheetByName("dBoard2");
//function copyData() {
//var rawD = source1.getRange(1,1,source1.getLastRow(),source1.getLastColumn()).getValues();
//Logger.log(rawD);
function setData() {
var rawD = source1.getRange(source1.getLastRow(),1,1,source1.getLastColumn()).getValues();
//Logger.log(limits);
var columnA = rawD[0][0];
var columnB = rawD[0][18];
var columnC = rawD[0][13];
var columnD = rawD[0][2];
var columnE = rawD[0][3]
var columnF = rawD[0][4];
var columnG = rawD[0][5];
var columnH = rawD[0][6];
var columnI = rawD[0][7];
var columnJ = rawD[0][8];
var columnK = rawD[0][9];
var columnL = rawD[0][11];
var columnM = rawD[0][12];
var outerArray = [columnA,
columnB,
columnC,
columnD,
columnE,
columnF,
columnG,
columnH,
columnI,
columnJ,
columnK,
columnL,
columnM];
Logger.log(columnA);
Logger.log(columnB);
Logger.log(outerArray);
dBoard.getRange(2,1,outerArray.length,outerArray.length);
dBoard.appendRow(outerArray);
}
I'm working on a little Google Apps Script that will export event data from a selected Google Calendar to a new Google Spreadsheet for a selected date range. One problem I'm having is that the times when copied over to the spreadsheet are off by three hours. Any suggestions as to how to handle this and display the event times correctly?
Here's my code so far: (It's a work-in-progress)
function doGet() {
var app = UiApp.createApplication();
var handler = app.createServerHandler("change");
var picker1 = app.createDatePicker().addValueChangeHandler(handler).setId("picker1");
var picker2 = app.createDatePicker().addValueChangeHandler(handler).setId("picker2");
var pickerpanel = app.createHorizontalPanel();
var panel = app.createVerticalPanel();
pickerpanel.add(picker1);
pickerpanel.add(picker2);
panel.add(pickerpanel);
var lb = app.createListBox(false).setId('lbCalSelId').setName('lbCalSelect');
lb.setVisibleItemCount(3);
var cals = CalendarApp.getAllCalendars();
for (var i=0; i<cals.length;i++) {
lb.addItem(cals[i].getName(),cals[i].getId());
}
panel.add(lb);
var button = app.createPushButton().setText("Export").setId("button");
var handler = app.createServerClickHandler('doExport').addCallbackElement(panel);
button.addClickHandler(handler);
panel.add(button);
app.add(panel);
return app;
}
function change(eventInfo) {
var app = UiApp.getActiveApplication();
if (eventInfo.parameter.picker1) {
UserProperties.setProperties({"DateRangeStart":eventInfo.parameter.picker1});
app.add(app.createLabel("Start date " + eventInfo.parameter.picker1));
}
else if (eventInfo.parameter.picker2) {
UserProperties.setProperties({"DateRangeEnd":eventInfo.parameter.picker2});
app.add(app.createLabel("End date" + eventInfo.parameter.picker2));
}
return app;
}
function doExport(eventInfo) {
var app = UiApp.getActiveApplication();
var calId = eventInfo.parameter.lbCalSelect;
var cal = CalendarApp.getCalendarById(calId);
var rangeStart = UserProperties.getProperty("DateRangeStart");
var rangeEnd = UserProperties.getProperty("DateRangeEnd");
app.add(app.createLabel("The button was clicked!"));
if (rangeStart && rangeEnd) {
app.add(app.createLabel("exporting..."));
var events = cal.getEvents(new Date(rangeStart), new Date(rangeEnd));
var eventsData = [];
var headerRow = ['Title','Start Time','End Time','Location','Description'];
for (var i=0; i < events.length; i++) {
var eventData = [];
eventData.push(events[i].getTitle());
eventData.push(events[i].getStartTime());
eventData.push(events[i].getEndTime());
eventData.push(events[i].getLocation());
eventData.push(events[i].getDescription());
eventsData.push(eventData);
}
var ss = SpreadsheetApp.create("Export of " + cal.getName() + " from " + rangeStart + " to " + rangeEnd);
var sheet = ss.getSheets()[0];
var destRange = sheet.getRange(1, 1, events.length, headerRow.length);
destRange.setValues(eventsData);
}
else {
app.add(app.createLabel("Range not specified."));
}
return app;
}
I figured it out.
I just set the timezone of the spreadsheet to the same timezone as the calendar and it worked like a charm.
ss.setSpreadsheetTimeZone(cal.getTimeZone());