Skip to content

Instantly share code, notes, and snippets.

@peterherrmann
Created May 30, 2012 13:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save peterherrmann/2836208 to your computer and use it in GitHub Desktop.
Save peterherrmann/2836208 to your computer and use it in GitHub Desktop.
Spreadsheet Splitter - Google Apps Script
// Creates new spreadsheets based on a column containing email addresses
// in the starting spreadsheet.
// Each new spreadsheet will contain the full set of rows for that email address.
// It will then be shared with that email address and a link emailed.
var EMAIL_COLUMN = 2; //Use the number: A=1,B=2,Z=26 etc
var ALSO_SHARE_WITH = ""; // Add any additional addresses here. Separated multiples with commas.
var NUM_HEADER_ROWS = 1; // The number of header rows.
// Do not change anything below this line
// 24 Nov 2010 - test mode works correctly after Google changes (session broke after Browser.msgBox)
var FLAG_COLUMN_HEADER_NAME = "Processed to spreadsheet";
var TEST = true;
var activeUserEmail = Session.getActiveUser().getEmail();
function doSegmentation() {
try{
// Get the currently selected sheet
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Test mode
var answer = Browser.msgBox("Run in test mode?",
"This will process the current sheet \"" + sheet.getName() +
"\". If you run in test mode, the full process is run as normal but any spreadsheets "+
"that are created are not shared and email is only ever sent to you " +
"and no one else. Do you want to run in test mode?",
Browser.Buttons.YES_NO_CANCEL);
switch (answer) {
case "yes":
TEST = true;
break;
case "no":
TEST = false;;
break;
case "cancel":
sheet.getParent().toast("Processing cancelled.");
return;
}
// Get index of flag column - create if necessary
var flagColumnIndex = getFlagColumnIndex_(sheet,FLAG_COLUMN_HEADER_NAME);
//Browser.msgBox(flagColumnIndex);
//Logger.log(flagColumnIndex);
// Get the full range of data to process
var range = sheet.getDataRange();
var values = range.getValues();
// get the first key to process
var key = getNextUnprocessedKey_(values, EMAIL_COLUMN-1, flagColumnIndex);
// get each key and process the rows containing that key
while (key) {
var rowIndexes = [];
rowIndexes = getUnprocessedByKey_(values, EMAIL_COLUMN-1, key, flagColumnIndex);
var message = "Processing " + key + ". " + rowIndexes.length + " rows to process.";
sheet.getParent().toast(message, "Progress");
//Browser.msgBox(rowIndexes.toString());
process_(sheet, values, key, rowIndexes, flagColumnIndex);
var values = range.getValues(); //reset values after processing (flags loaded)
key = getNextUnprocessedKey_(values, EMAIL_COLUMN-1, flagColumnIndex);
}
sheet.getParent().toast("Processing completed successfully.", "Progress", -1);
} catch(error){
//sheet.getParent().toast("Error: " + error, -1);
Browser.msgBox("Error: " + error);
//logToSheet_("Error (doEmailToBeDeletedUsers): " + error);
}
}
function process_(sheet, values, key, rowIndexes, flagColumnIndex) {
// rowIndexes is required so we can "stamp" the rows as processed
//create spreadsheet
var ssNew = SpreadsheetApp.create(sheet.getParent().getName()+" for " + key);
var collabs = ALSO_SHARE_WITH ? key + ", "+ ALSO_SHARE_WITH : key;
// bug (logged) with emailing collabs so we do it manually later in this function
// http://code.google.com/p/google-apps-script-issues/issues/detail?id=170
if (!TEST) {
ssNew.addCollaborators(collabs, {editorAccess:true, emailInvitations:false});
}
var sheetNew = ssNew.getSheets()[0];
// Set header rows
var headerValues = sheet.getRange(1,1,NUM_HEADER_ROWS, sheet.getLastColumn()-1).getValues();
sheetNew.getRange(1,1,NUM_HEADER_ROWS, sheet.getLastColumn()-1).setValues(headerValues);
// get rows to copy
var rowsToCopy = [];
for(var i = 0; i < rowIndexes.length ; i++) {
rowsToCopy.push(values[rowIndexes[i]]);
}
// add rows to sheet
sheetNew.getRange(NUM_HEADER_ROWS+1,1,rowsToCopy.length,rowsToCopy[0].length).setValues(rowsToCopy);
// tweak example - set the fifth column to 500pixels wide
//sheetNew.setColumnWidth(4, 500)
//send ss link email
var testmsg = TEST ? "This is a test that would have been sent to " + collabs + "." : "";
var html = "Here is a link to <a href=\"" + ssNew.getUrl() + "\">" +
ssNew.getName() + "</a><br><br>";
var body = "Here is a link to "+ssNew.getUrl()+": "+ssNew.getName()+"\n\n";
var recipients = TEST ? activeUserEmail : collabs;
//Browser.msgBox("recipients:"+recipients+ "."); //debug
MailApp.sendEmail(recipients, ssNew.getName(),
testmsg + "\n\n" + body, {htmlBody: testmsg + "<br><br>" + html});
// mark each row as processed
for(var i = 0; i < rowIndexes.length ; i++) {
sheet.getRange(rowIndexes[i]+1, flagColumnIndex+1).setValue(ssNew.getUrl());
}
}
function getFlagColumnIndex_(sheet, headerName) {
// Looks for the specified column header name in the first row of the sheet
// and returns the column index (0 based index).
// Creates column if required (appends to end). Returns -1 if not found.
var row = 1; // look in the first row only
var headerColumnIndex = -1;
var value = "";
for (var i = 0; i < sheet.getLastColumn(); ++i) {
value = sheet.getRange(row, i+1).getValue();
if (value === headerName) {
var headerColumnIndex = i;
}
}
// if no column found, create one
if (headerColumnIndex === -1) {
sheet.insertColumnsAfter(sheet.getLastColumn(), 1);
var headerColumnIndex = sheet.getLastColumn();
sheet.getRange(1,headerColumnIndex+1).setValue(headerName);
}
return headerColumnIndex;
}
function getNextUnprocessedKey_(values, keyColumnIndex, flagColumnIndex) {
// Returns the value of the key column where the data in flagColumnIndex is blank
// Process each row (not header so start at 1)
var key = "";
for(var i = NUM_HEADER_ROWS; i < values.length ; i++) {
var value = values[i][flagColumnIndex];
if (value === "") {
return values[i][keyColumnIndex];
}
}
}
function getUnprocessedByKey_(values, keyColumnIndex, key, flagColumnIndex) {
// Returns an array containing row indexes (0 based) of rows
// where the row key matches and the flagColumnIndex is blank
// Process each row (not header so start at 1)
var rows = [];
for(var i = NUM_HEADER_ROWS; i < values.length ; i++) {
var keyVal = values[i][keyColumnIndex];
var flagVal = values[i][flagColumnIndex];
if ((flagVal === "") && (keyVal === key)) {
rows.push(i);
}
}
return rows;
}
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "Create split sheets...", functionName: "doSegmentation"} ];
ss.addMenu("Spreadsheet Splitter", menuEntries);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment