【问题标题】:I need to split a Google Sheet into multiple tabs (sheets) based on column value我需要根据列值将 Google 表格拆分为多个选项卡(表格)
【发布时间】:2020-03-13 17:29:38
【问题描述】:

我已经搜索了许多可能的答案,但似乎找不到一个有效的答案。我有一个大约 1600 行的 Google 表格,我需要根据标题为“房间”的列中的值将其分成大约 70 个不同的选项卡(每个选项卡大约 20-30 行)。我一直在排序,然后剪切和粘贴,但是对于 70 多个标签,这非常乏味。

我可以使用查询功能,但我仍然需要创建一个新选项卡,粘贴该功能并更新该特定选项卡的参数。

这个脚本看起来很接近:

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);
}

但我总是在第 51 行或第 52 行收到意外的令牌错误:

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

(显然列名等对于我的数据不一定正确,我尝试更改它们以匹配我需要的内容。不确定这是否是问题的一部分。)

这是我的数据示例:https://docs.google.com/spreadsheets/d/1kpD88_wEA5YFh5DMMkubsTnFHeNxRQL-njd9Mv-C_lc/edit?usp=sharing 这应该根据房间返回两个单独的选项卡/工作表。

我显然不是程序员,也不知道 Visual Basic 或 Java 什么的。我只知道如何用谷歌搜索和复制东西......令人惊讶的是,我经常让它工作。

如果您能提供帮助,请告诉我您还需要什么。

【问题讨论】:

    标签: google-apps-script google-sheets google-apps-script-editor


    【解决方案1】:

    试试下面的代码:

    • 'splitSheetIntoTabs' 会将您的主工作表拆分为单独的工作表,每张 30 行。它只会复制内容而不是背景颜色等。
    • “deleteTabsOtherThanMaster”将恢复“splitSheetIntoTabs”所做的更改。此函数将有助于还原 splitSheetIntoTabs 所做的更改。

    function splitSheetIntoTabs() {
       var sheet = SpreadsheetApp.getActiveSheet();
      var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
      var header = rows[0];
      var contents = rows.slice(1);
      var totalRowsPerSheet = 30; // This value will change no of rows per sheet
      
      //below we are chunking the toltal row we have into 30 rows each
      var contentRowsPerSheet = contents.map( function(e,i){ 
         return i%totalRowsPerSheet===0 ? contents.slice(i,i+totalRowsPerSheet) : null; 
    }).filter(function(e){ return e; });
    
      contentRowsPerSheet.forEach(function(e){
        //crate new sheet here
      var currSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet();
        
        //append the header
        currSheet.appendRow(header);
        
        //populate the rows
        e.forEach(function(val){
          currSheet.appendRow(val);
        });
        
      });
      
    
    }
    
    
    // use this function revert the sheets create by splitSheetIntoTabs()
    
    function deleteTabsOtherThanMaster() {
      var sheetNotToDelete ='Master';
        var ss = SpreadsheetApp.getActive();
      
      
        ss.getSheets().forEach(function(sheet){
          if(sheet.getSheetName()!== sheetNotToDelete)
          {
            ss.deleteSheet(sheet);
          }
        });
    
    
    }

    【讨论】:

    • @cincinnance 如果这符合您的需要,请将其标记为已回答。
    • 谢谢你,维涅什!有没有办法按标题为 set_name 的列中的值进行拆分?如果我的问题不清楚,我很抱歉?。为了清楚起见,我现在对其进行了编辑。
    • 您的意思是文件夹名称列吗?该表中没有可用的 set_name 列。您是否要根据该列对所有行进行排序,然后将它们拆分为单独的工作表?
    • Vignesh,让我再次道歉。我是一个白痴。我将列名更改为“房间”以尝试与我找到的示例脚本相匹配。这是我需要的专栏。那个叫“房间”。是的,我需要为该列中的每个值创建一个单独的工作表/选项卡。首先对 master 进行排序是有意义的,因为这可能会更容易。
    【解决方案2】:

    我使用的是 Kessy 的漂亮脚本,但是当数据变得非常大时开始遇到问题,脚本超时。我开始寻找减少脚本读取/写入电子表格的次数(而不是一次读取/写入一行)的方法,并找到了这篇文章https://stackoverflow.com/a/42633934

    使用此原则并更改脚本中的循环以在循环中包含循环有助于减少这些调用。这意味着您还可以避免第二次调用追加行(“else”)。我的脚本与示例有点不同,但基本上结束于:

    `for (var i = 1; i < theEmails.length; i++) {    
    //Ignore blank Emails and sheets created
    if (theEmails[i][0] !== "" && !completedSheets.includes(theEmails[i][0])) { 
    
      //Set the Sheet name = email address.  Index the sheets so they appear last.
    
        var currentSheet = theWorkbook.insertSheet(theEmails[i][0],4+i);
      
      //append the header
      
      //To avoid pasting formulas, we have to paste contents
      headerFormat.copyTo(currentSheet.getRange(1,1),{contentsOnly:true});
    
      //Now here find all the rows containing the same email address and append them
      var theNewRows =[];
      var b=0;
      for(var j = 1; j < rows.length; j++)
    {
     
    if(rows[j][0] == theEmails[i][0]) {
      
      theNewRows[b]=[];//Initial new array
      theNewRows[b].push(rows[j][0],rows[j][1],rows[j][2],rows[j][3],rows[j][4],rows[j][5],rows[j][6],rows[j][7]);
      b++;
    }
    }var outrng = currentSheet.getRange(2,1,theNewRows.length,8); //Make the output range the same size as the output array
    outrng.setValues(theNewRows);
    

    我发现一个约 1000 行的表超时,但使用新脚本需要 6.5 秒。它可能不是很整洁,因为我只涉足脚本,但也许它有帮助。

    【讨论】:

      【解决方案3】:

      我已经完成了这个脚本,成功获取了每个房间并创建了一个具有相应房间名称的新工作表,并添加了同一个房间的所有行。

      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]);
          }
      
        }
      
      }
      

      请对其进行测试,不要犹豫对改进发表评论。

      【讨论】:

      • 这就像一个魅力!你是救命稻草,非常感谢!每次我必须这样做时,从字面上节省我的工作时间。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      • 2021-05-21
      • 1970-01-01
      • 2022-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多