【问题标题】:Auto Archive Schedule; Time-based Trigger自动存档计划;基于时间的触发
【发布时间】:2019-07-10 23:26:50
【问题描述】:

我被要求创建一个实时的 Google 表格电子表格来跟踪我们院子里的工作时间表。我没有使用脚本的经验,但发现我可以对工作表进行编程而不是隐藏公式,这样会产生更清晰的结果。我已经能够使工作表自行组织,并且能够手动将其归档(onEdit)。我正在寻找的是让它在凌晨 1 点自动运行代码,这样当我们上班时,它会根据某个列中的单元格值进行存档。

这是我的 onEdit 脚本的一个示例,但当有人试图检查“是”列时,会出现一些滞后,并可能导致检查错误的单元格,然后我手动更正。

function onEdit() {
  var sheetNameToWatch = "Schedule";

  var columnNumberToWatch = 28;
  var valueToWatch = "Yes";
  var sheetNameToMoveTheRowTo = "Archive";

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getActiveCell();

  if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {

    var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
    var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
    sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
    sheet.deleteRow(range.getRow());
  }
}

所以这段代码以 100% 的失败运行,但保存并执行,老实说,我不知道为什么。可能是我误解了我需要在“功能”区域之后插入的值。我确实使用“自动存档”触发器进行了此设置,该触发器在工作表上创建了一个带有“运行”选项的菜单按钮,但是当您单击它时,它只会在第 28 列中使用“是”的最后一行(每次按下按钮将移动 1 行,直到所有行都被移动),并且该按钮不适用于工作表的其他用户。

function createTrigger() {
  ScriptApp.newTrigger("Move Archive") //Move Archive is the name of the script
    .timeBased()
    .everyMinutes(1) // only set to 1 minute for testing, I can change this out for a daily timer
    .create();
}


function myFunction() {
  var sheetNameToWatch = "Schedule"; // "schedule" is the sheet we enter info on

  var columnNumberToWatch = 28; //Column is "AB"
  var valueToWatch = "Yes";
  var sheetNameToMoveTheRowTo = "Archive"; //"Archive is the sheet the info is sent to"

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getActiveCell();

  if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {

    var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
    var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
    sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange); // I get its programmed for last row with "Yes" here, unsure on how to change this.
    sheet.deleteRow(range.getRow());

    function myfunction() {
      ScriptApp.deleteTrigger("Move Archive"); // could have wrong value here

    }
  }
}

我想要的只是根据第 28 列 (AB) 中的“是”值“存档”的工作表。我希望具有该列值的每一行在凌晨 1 点自动存档。任何帮助表示赞赏。如果有人甚至想为初学者推荐一本书或数字指令,那就太好了。

【问题讨论】:

  • 感谢您澄清这一点,很高兴我被允许在这里发帖。为了弄清楚如何安装触发器,我可以做到这一点,我相信我的问题是知道如何填写触发器中的值以实现我正在寻找的结果。我阅读了您链接的内容,但它没有解释我必须添加到触发器中的括号以使其与我的脚本交互的值。我的另一个问题是,一旦触发器工作,它可能只会拉出符合条件的最后一行,我希望它拉出符合条件的所有行。我相信我需要一个循环或不同的脚本。
  • 文档说newTrigger 将函数名称作为参数,所以在你的情况下,如果你有function myFunction(){,它将是.newTrigger('myFunction')
  • 好的,这是有道理的。我也确实尝试过这种方式,但床单上什么也没发生。不过,我确实看到在项目页面上创建并删除了触发器。
  • 如果您的工作表或代码中有任何敏感信息,请务必将其删除,但能否提供指向工作表副本的链接?如果没有可查看的结构,可能很难可视化电子表格
  • 在问题中添加了链接。

标签: google-apps-script google-sheets triggers archive schedule


【解决方案1】:

您有四个项目文件,每个文件都包含同名的脚本,执行相同或相似的任务。您正在经历滞后,因为您有多个简单且可安装的同名脚本。本质上,它们都试图同时执行。

以下答案应被视为您的情况的一种可能解决方案。

这个脚本的元素是:

  • 只有一个项目文件。不必要的项目文件已被删除。
  • 只有一个函数。
  • 该函数是一个单一的“简单”触发器 (onEdit(e)),它利用了 onEdit 返回的各种事件对象。没有可安装的触发器,并且所有/所有可安装的触发器都已被删除。
  • 该函数更新问题中描述的“计划”和“存档”表;然后对“Schedule”和“Archive”工作表进行排序。
  • 如果“Railcars”工作表有变化,该函数会对该工作表进行排序。

function onEdit(e) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var testrange = e.range;
  var testsheet = testrange.getSheet();
  var testsheetname = testsheet.getSheetName();
  var testrow = testrange.getRow();
  var testcolumn = testrange.getColumn();
  var testvalue = e.value;
  var testsheetLC = testsheet.getLastColumn();
  var testsheetRange = testsheet.getRange(testrow,1,1,testsheetLC);
  //Logger.log("DEBUG: the test sheet range is "+testsheetRange.getA1Notation()); 
  //Logger.log("DEBUG: Range: "+testrange.getA1Notation());
  //Logger.log("DEBUG: The row is "+testrow+", and the column is "+testcolumn);
  //Logger.log("DEBUG: The spreadheetsheet is "+e.source.getName()+", the sheet name is  "+testsheet+", the range = "+testrange.getA1Notation()+", and the new value = "+testvalue);
  //Logger.log(JSON.stringify(e));

  // Copy/Paste to Schedule/Archive
  var sheetNameSchedule = "Schedule";
  var colNumberSchedule = 28;
  var valueSchedule = "Yes";
  var sheetNameArchive = "Archive";

  // Sort Schedule
  var sortSchedule = [{column: 1, ascending: true},{column: 2, ascending: true},{column: 7, ascending: false}];// date // Appt (time) // Type (Out/In/RR)
  // Sort Railcars
  var sheetNameRailcars = "Railcars";
  var sortRailcars = [{column: 1, ascending: true}];

  if (testsheetname === sheetNameSchedule && testcolumn === colNumberSchedule && testvalue === valueSchedule){
    // this is a match
    // Logger.log("DEBUG: this was a match");

    // copy/paste to archive
    var targetSheet = ss.getSheetByName(sheetNameArchive);
    var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
    //Logger.log("DEBUG: the target range is "+targetRange.getA1Notation());
    testsheetRange.moveTo(targetRange);
    testsheet.deleteRow(testrow);

    // sort the Schedule Sheet
    var Avals = testsheet.getRange("A1:A").getValues();
    var Alast = Avals.filter(String).length;
    //Logger.log("DEBUG: The last row of content (in column A) = "+Alast+", and the last column = "+testsheetLC);
    var sortrange = testsheet.getRange(2,1,Alast-1,testsheetLC);
    //Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
    sortrange.sort(sortSchedule);

    // sort the Archive Sheet
    var ATvals = targetSheet.getRange("A1:A").getValues();
    var ATlast = ATvals.filter(String).length;
    //Logger.log("DEBUG: The last row of content (in column A) = "+ATlast+", and the last column = "+testsheetLC);
    var sortrange = targetSheet.getRange(2,1,ATlast-1,testsheetLC);
    //Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
    sortrange.sort(sortSchedule);
  }
  else if (testsheetname === sheetNameRailcars){

    // sort the sheet
    var Avals = testsheet.getRange("A1:A").getValues();
    var Alast = Avals.filter(String).length;
    //Logger.log("DEBUG: The last row of content (in column A) = "+Alast+", and the last column = "+testsheetLC);
    var sortrange = testsheet.getRange(2,1,Alast-1,testsheetLC);
    //Logger.log("DEBUG: the sort range = "+sortrange.getA1Notation());
    sortrange.sort(sortRailcars);
  } 

}

【讨论】:

    【解决方案2】:

    您可以设置一个可安装的触发器以在每天凌晨 1 点运行此功能:

    function scheduleToArchive() {
      var sheet = SpreadsheetApp.getActiveSpreadsheet();
      var schedule = sheet.getSheetByName("Schedule");
      var archive = sheet.getSheetByName("Archive");
      var scheduleData = schedule.getRange(2, 1, (sheet.getRange('A:A').getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()), 28);
    
      for (row = 2; row <= scheduleData.getNumRows(); row++){
        var data = schedule.getRange(row, 1, 1, 28).getValues();
    
        if (data[0][27] == 'Yes'){
         archive.getRange((archive.getLastRow() + 1), 1, 1, 28).setValues(data);
        }    
        schedule.getRange(row, 1, 1, 28).clear();
      }  
    }
    
    

    在您的电子表格中,当getDataRange() 在名为“Schedule”的工作表上运行时,即使前 20 行中只有数据,它也会返回第 631 行作为最后一行包含数据,所以为了解决这个问题,我我改用SpreadsheetApp.Direction.DOWN 并在A 列上运行它。

    【讨论】:

    • 您好,这很好用,我需要做的就是将复制的行从“计划”表中删除,然后将其移动到“存档”表。我会尝试完成这项工作,但如果有人可以让我知道最简单的方法,我将不胜感激。明白了,补充:schedule.deleteRow(row);
    • @WarrenRoss 不要使用deleteRow() - 你以后会遇到麻烦,因为没有任何行,所以无法输入数据,getRange() 会抛出一个错误。获取范围并改用clear(),因为这会清除数据而不完全删除行。我已经更新了我的答案,以便脚本在运行时自动清除行。
    • 所以我测试了清除功能,但它不会在清除后重新使用工作表。我想我会根据需要使用删除和添加行。我想我可以添加一个由 clear 驱动的触发器,但只需单击一下即可每隔几个月添加 1000 行。感谢大家对此的帮助!
    • @WarrenRoss 啊,是的,对不起-我将它包含在条件中而不是在它之外。我已经修复了它,所以如果你想自动化它而不必担心将来添加行,它现在应该可以工作了。
    • 您好,所以直到本周为止,这一直运行良好,在凌晨 1 点触发器关闭后,似乎线路丢失(它们不会移动到存档表,而是从日程表中删除) .以这样的写法,“是”列是否需要按顺序勾选?例如:第 2 行和第 4 行被勾选为“是”,但第 3 行不是。它会毫无问题地移动第 2 行和第 4 行吗?
    猜你喜欢
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多