google-apps-scriptgoogle-sheetsgoogle-apps-script-editor

I need to split a Google Sheet into multiple tabs (sheets) based on column value


I have searched many possible answers but cannot seem to find one that works. I have a Google Sheet with about 1600 rows that I need to split into about 70 different tabs (with about 20-30 rows in each one) based on the value in the column titled “room”. I have been sorting and then cutting and pasting but for 70+ tabs this is very tedious.

I can use the Query function but I still need to create a new tab, paste the function and update the parameter for that particular tab.

This script seemed pretty close:

ss = SpreadsheetApp.getActiveSpreadsheet();
itemName = 0;
itemDescription = 1;
image = 2;
purchasedBy = 3;
cost = 4;
room = 5;
isSharing = 6;
masterSheetName = "Master";

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Update Purchases')
      .addItem('Add All Rows To Sheets', 'addAllRowsToSheets')
      .addItem('Add Current Row To Sheet', 'addRowToNewSheet')
      .addToUi();
}

function addRowToNewSheet() {
  var s = ss.getActiveSheet();
  var cell = s.getActiveCell();
  var rowId = cell.getRow();
  var range = s.getRange(rowId, 1, 1, s.getLastColumn());
  var values = range.getValues()[0];
  var roomName = values[room];
  appendDataToSheet(s, rowId, values, roomName);
}

function addAllRowsToSheets(){
  var s = ss.getActiveSheet();
  var dataValues = s.getRange(2, 1, s.getLastRow()-1, s.getLastColumn()).getValues();
  for(var i = 0; i < dataValues.length; i++){
    var values = dataValues[i];
    var rowId = 2 + i;
    var roomName = values[room];
    try{
      appendDataToSheet(s, rowId, values, roomName);
    }catch(err){};
  }
}

function appendDataToSheet(s, rowId, data, roomName){
  if(s.getName() != masterSheetName){
    throw new Error("Can only add rows from 'Master' sheet - make sure sheet name is 'Master'");
  }
  var sheetNames = [sheet.getName() for each(sheet in ss.getSheets())];
  var roomSheet;
  if(sheetNames.indexOf(roomName) > -1){
    roomSheet = ss.getSheetByName(roomName);
    var rowIdValues = roomSheet.getRange(2, 1, roomSheet.getLastRow()-1, 1).getValues();
    for(var i = 0; i < rowIdValues.length; i++){
      if(rowIdValues[i] == rowId){
        throw new Error( data[itemName] + " from row " + rowId + " already exists in sheet " + roomName + ".");
        return;
      }
    }
  }else{
    roomSheet = ss.insertSheet(roomName);
    var numCols = s.getLastColumn();
    roomSheet.getRange(1, 1).setValue("Row Id");
    s.getRange(1, 1, 1, numCols).copyValuesToRange(roomSheet, 2, numCols+1, 1, 1);
  }
  var rowIdArray = [rowId];
  var updatedArray = rowIdArray.concat(data);
  roomSheet.appendRow(updatedArray);
}

But I always get an unexpected token error on line 51 or 52:

var sheetNames = [sheet.getName() for each(sheet in ss.getSheets())]; 

(And obviously the column names, etc. are not necessarily correct for my data, I tried changing them to match what I needed. Not sure if that was part of the issue.)

Here is a sample of my data: https://docs.google.com/spreadsheets/d/1kpD88_wEA5YFh5DMMkubsTnFHeNxRQL-njd9Mv-C_lc/edit?usp=sharing This should return two separate tabs/sheets based on room .

I am obviously not a programmer and do not know Visual Basic or Java or anything. I just know how to google and copy things....amazingly I often get it to work.

Let me know what else you need if you can help.


Solution

  • I have done this script that successfully gets each room and creates a new sheet with the corresponding room name and adding all the rows with the same room.

    function myFunction() {
      var sheet = SpreadsheetApp.getActiveSheet();
    
      // This var will contain all the values from column C -> Room
      var columnRoom = sheet.getRange("C:C").getValues();
    
      // This var will contain all the rows
      var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
    
      //Set the first row as the header
      var header = rows[0];
    
      //Store the rooms already created
      var completedRooms = []
    
      //The last created room
      var last = columnRoom[1][0]
    
    
      for (var i = 1; i < columnRoom.length; i++) {    
    
        //Check if the room is already done, if not go in and create the sheet
        if(!completedRooms.includes(columnRoom[i][0])) {
    
          //Set the Sheet name = room (except if there is no name, then = No Room)
          if (columnRoom[i][0] === "") {
            var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("No Room");
          } else {
            var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(columnRoom[i][0]);
          }
    
    
          //append the header
          currentSheet.appendRow(header);
          currentSheet.appendRow(rows[i]);
          completedRooms.push(columnRoom[i][0])
          last = columnRoom[i][0]
        } else if (last == columnRoom[i][0]) {
    
        // If the room's sheet is created append the row to the sheet
    
    
          var currentSheet = SpreadsheetApp.getActiveSpreadsheet()
          currentSheet.appendRow(rows[i]);
        }
    
      }
    
    }
    

    Please test it and don't hesitate to comment for improvements.