【问题标题】:Applying a formula to all cells in a column, unless equals x将公式应用于列中的所有单元格,除非等于 x
【发布时间】:2023-03-14 09:41:01
【问题描述】:

我正在尝试将公式应用于列,但仅当单元格不包含特定值(EMAIL SENT)时,我有一个脚本,当行在“AF”列中“发送电子邮件”时发送电子邮件,并且将其替换为“EMAIL SENT”以避免重新发送,我需要它来跳过其中包含“EMAIL SENT”的单元格。

这是我到目前为止的脚本,但它重写了单元格并将单元格重置为“发送电子邮件”。 提前致谢。
初级脚本编写者。
ps 或让这个公式从 AF 列中的第一个空单元格开始。

  var sss4 = SpreadsheetApp.openById('<ID>');
  var ss4 = sss4.getSheetByName('Results');
  ss4.getRange("AF2").setFormula('=IF(((AND(OR(I2="YOUR TRIP DWL",I2="MEGA PACK DWL (YT + AA + BONUS)"),M2<=0,AA2<>"",AE2<>""))), "Send Email", "Wait")');
  var lr4 = ss4. getLastRow();
  var filldownrange4 = ss4.getRange(2, 32, lr4-1);
  ss4. getRange("AF2").copyTo(filldownrange4);

【问题讨论】:

  • 您是否尝试过“仅代码”解决方案?这有帮助还是您仍然遇到问题?

标签: google-apps-script google-sheets


【解决方案1】:

我建议将公式直接放入电子表格中,而不是通过脚本插入公式。这将大大简化您的代码。

我采用了你的公式并添加了一些元素:

1 - 将 AF 列转换为在发送电子邮件时更新的列。
2 - 添加了“状态”列(可能是 AG 列??)。这就是公式的所在。
3 - 将公式转换为ARRAYFORMULA。请注意,公式中的每个范围都包含一整列(例如 I2:I)。这也需要将AND 替换为“*”,将OR 替换为“+”。请参阅下面的说明。
4 - 添加了ARRAY_CONSTRAIN,以便仅在添加新数据行时添加公式。如果这不在这里,那么公式将显示在工作表底部的每一行列中 - 看起来不是很好,而且有点令人反感。


=ARRAY_CONSTRAIN(ArrayFormula(if(M2:M="EMAIL SENT","EMAIL SENT",IF(((I2:I="YOUR TRIP DWL")+(I2:I="MEGA PACK DWL (YT + AA + BONUS)"))*(J2:J<=0)*(K2:K<>"")*(L2:L<>""), "Send Email", "Wait"))),COUNTA(I2:I),1)

这是我的布局和公式结果的屏幕截图。


逻辑是这样的:

  1. 检查 M 列(您的 AF 列)。评估是否已发送电子邮件。如果是,则什么也不做;如果不是,则评估是否该发送电子邮件。

  2. 如果尚未发送电子邮件,则评估某些字段的状态。

    • 第 I 列(您的第 I 列) - 它是否包含“YOUR TRIP DWL”或“MEGA PACK DWL (YT + AA + BONUS)”。如果是,则继续,否则“等待”。

    • 检查以下每一列的计算结果是否为真。

      • J 列(您的 M 列)
      • K 列(您的 AA 列)“”(非空白)
      • L 列(您的 AE 列)“”(非空白)
      • 如果这些都评估为真,则“发送电子邮件”,否则“等待”。
  3. 显示公式结果的行数由ARRAY_CONSTRAIN 和参数COUNTA(I2:I) 控制。这会计算第 I 列(您的第 I 列)中包含内容的行数。选择此列是假设 L 列中始终存在一个值。如果不是这种情况,则选择另一个始终包含内容的单元格/列。如果您选择具有数值的单元格/列,则可能需要将 COUNTA 更改为 COUNT

ARRAYFORMULA 公式只输入一个单元格(相当于“状态”列中的单元格 AG2)。 ARRAYFORMULA 逐行计算公式并自动在列的每一行中显示结果。 ARRAY_CONSTRAIN 约束结果;在我们的例子中,它仅限于那些有值的行。

IF 语句中的 ANDOR 发生了什么?

请注意,IF 语句实际上并不包含ANDOR 函数。显然,它们对ARRAYFORMULA 产生了无效的影响。但要归功于Max Makhrov in "Google Sheets ARRAYFORMULA with nested if statements" 他建议的地方。

Replace AND with * and OR with +

对代码的影响

您的代码应该循环并评估“状态”列。
如果值为“发送电子邮件”,则发送电子邮件并将“状态”列更新为“电子邮件已发送”。否则,什么也不做。


更新:代码更改

这是符合建议公式的代码。该代码是自我记录的,并且相当容易遵循。大致流程如下。

1 - 允许用户变量
2 - 远程打开电子表格
3 - 计算数据的行数
4 - 按行循环遍历数据
5 - 如果单元格值 = "Send Email",则发送电子邮件,并使用 "EMAIL SENT" 更新相邻列的值

function so_52680239() {

  // Declare user variables
  // SpreadsheetID
  var ResultsSheetID = "1Iz-qmOnzZp4EAmGzWJORNpJGkueYzGFUTkpUZ9g3-as";
  // SheetName
  var SheetName = "Results";
  // Column letter for the Status Column
  var StatusColumnLetter = "N";
  // Start row for the Status Column
  var StatusHeaderRow = 1;


  // open the Results Spreadsheet
  // Supply the ID
  var ResultsSheet = SpreadsheetApp.openById(ResultsSheetID);
  var Results_ss = ResultsSheet.getSheetByName(SheetName);

  // Convert the column letter for Status Column to a number
  var StatusColumnNumber = letterToColumn(StatusColumnLetter);
  //Logger.log("StatusColumnNumber = "+StatusColumnNumber);

  // Create a string variable range for the Status Column
  var StatusStartRange = StatusColumnLetter+StatusHeaderRow+":"+StatusColumnLetter;
  //Logger.log("StatusStartRange = "+StatusStartRange);

  // Get the last row with content in the StatusColumn
  var LastRowvals = Results_ss.getRange(StatusStartRange).getValues();
  var LastDataRow = LastRowvals.filter(String).length;
  //Logger.log('Last row = '+LastDataRow);

  // declare the search range
  var searchRange = Results_ss.getRange(StatusHeaderRow+1,StatusColumnNumber, LastDataRow-1);
  //var searchRangeA1 = searchRange.getA1Notation();
  //Logger.log('searchRangeA1 = '+searchRangeA1);

  // Get array of values in the search Range
  var rangeValues = searchRange.getValues();


  // Loop through array and if condition met, send email
  // Note, only one column of data so no looping by column
    for ( j = 0 ; j < LastDataRow - 1; j++){
      if(rangeValues[j][0] === 'Send Email'){
        // do stuff
        // insert code to send email
        //Logger.log("j = "+j+", value = "+rangeValues[j][0]+", so Send Email");
        // Update your Column AF (one column to the left of the formula results column) with "EMAIL SENT"
        Results_ss.getRange(StatusHeaderRow+1+j,StatusColumnNumber).offset(0, -1).setValue('EMAIL SENT');
      }else {
        // do Nothing
        //Logger.log("j = "+j+", value = "+rangeValues[j][0]+", so do nothing");
      }; 
    };
}

//Utility to convert a column letter to a column number
function letterToColumn(letter)
{
  var column = 0, length = letter.length;
  for (var i = 0; i < length; i++)
  {
    column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
  }
  return column;
}

屏幕截图 - 运行代码之后。注意记录#2 已更新。


学分: yagisanatode.com 获取快速/高效的数据更新方式:Google Apps Script – Iterating Through Ranges in Sheets the Right and Wrong Way


纯代码解决方案

如果无法为公式手动更新电子表格,脚本可以执行相同的任务。

假设:I 列始终包含数据;这用于计算要处理的数据行数。

Provisio:如果在运行脚本时,AF2 中的相关单元格为空,则将在该单元格中插入公式。然后该公式将评估数据,结果可能是它显示“发送邮件”值。但是,没有规定可以在同一更新例程中发送邮件。

我会留给提问者来决定他们如何选择处理这件事。

function so_52680239_02() {

    // Declare user variables
    // SpreadsheetID
    var ResultsSheetID = "1ILmQ5cAwRD0Va0lPKcAhr7OTvwLaX_UtFCJ8EEL4TwM";
    // SheetName
    var SheetName = "Results01";
    // Column letter for the Status Column
    var StatusColumnLetter = "M";
    // Start row for the Status Column
    var StatusHeaderRow = 1;
    // Column letter for the TripType (assume that there is always data in this cell)
    var TripTypeColumnLetter = "I";


    // open the Results Spreadsheet
    // Supply the ID
    var ResultsSheet = SpreadsheetApp.openById(ResultsSheetID);
    var Results_ss = ResultsSheet.getSheetByName(SheetName);

    // Convert the column letter for Status Column to a number
    var StatusColumnNumber = letterToColumn(StatusColumnLetter);
    // Logger.log("StatusColumnNumber = "+StatusColumnNumber); //DEBUG

    // Convert the column letter for Trip Type Column to a number
    var TripTypeColumnNumber = letterToColumn(TripTypeColumnLetter);
    // Logger.log("TripTypeColumnNumber = "+TripTypeColumnNumber);// DEBUG

    // Create a string variable range for the Status Column
    var StatusStartRange = StatusColumnLetter + StatusHeaderRow + ":" + StatusColumnLetter;
    //  Logger.log("StatusStartRange = "+StatusStartRange); // DEBUG

    // Create a string variable range for the Trip Type Column
    var TripTypeRange = TripTypeColumnLetter + StatusHeaderRow + ":" + TripTypeColumnLetter;
    //  Logger.log("TripTypeRange = "+TripTypeRange); // DEBUG

    // Get the last row with content in the Trip Type Column
    var TripLastRowvals = Results_ss.getRange(TripTypeRange).getValues();
    var TripLastDataRow = TripLastRowvals.filter(String).length;
    //  Logger.log('Last trip row = '+TripLastDataRow);// DEBUG

    // Define the formula
    var myformula = '=IF(((AND(OR(I' + row + '="YOUR TRIP DWL",I' + row + '="MEGA PACK DWL (YT + AA + BONUS)"),M' + row + '<=0,AA' + row + '<>"",AE' + row + '<>""))), "Send Email", "Wait")';

    // declare the search range in Column AF
    var searchRange = Results_ss.getRange(StatusHeaderRow + 1, StatusColumnNumber, TripLastDataRow - 1);
    // Logger.log('searchRange = '+searchRange.searchRangeA1);  //DEBUG

    //Get array of values in the search Range
    var rangeValues = searchRange.getValues();
    //Logger.log("rangevalues = "+rangeValues)

    // establish some variablkes for use in the loop
    var emailformula = "";
    var emailformularange = "";

    // loop for email formula
    for (var row = 0; row < TripLastDataRow - 1; row++) {

        if (rangeValues[row][0] == "") {
            // cell is empty, insert formula

            emailformula = '=IF(((I' + (row + 2) + '="YOUR TRIP DWL")+(I' + (row + 2) + '="MEGA PACK DWL (YT + AA + BONUS)"))*(J' + (row + 2) + '<=0)*(K' + (row + 2) + '<>"")*(L' + (row + 2) + '<>""), "Send Email", "Wait")';
            emailformularange = '' + StatusColumnLetter + (row + 2) + ''
            var rangeList = Results_ss.getRangeList([emailformularange]);
            rangeList.setFormula(emailformula);
            //Logger.log("row = "+row+", value = "+rangeValues[row][0]+", Action: Cell is empty, so insert formula in "+emailformularange);//DEBUG

        } else if (rangeValues[row][0] == "EMAIL SENT") {
            //do nothing

            //Logger.log("row = "+row+", value = "+rangeValues[row][0]+", Action: Email already sent so do nothing"); // DEBUG

        } else if (rangeValues[row][0] == "Wait") {

            //do nothing

            //Logger.log("row = "+row+", value = "+rangeValues[row][0]+", Action: Wait, so do nothing"); //DEBUG

        } else if (rangeValues[row][0] == "Send Email") {

            // Send mail

            emailformularange = '' + StatusColumnLetter + (row + 2) + ''
            Results_ss.getRange(emailformularange).setValue('EMAIL SENT');
            // Logger.log("row = "+row+", value = "+rangeValues[row][0]+", Action: Send Mail and update cell "+emailformularange+" to 'EMAIL SENT'");  //DEBUG

        }
    }
}

【讨论】:

  • 感谢 Tedinox 的回复,不幸的是,我无法将公式直接放入电子表格中,因为该表格是从使用下面的脚本购买的其他表格中添加的,但它不带它是附加到该工作表中单元格的公式,我需要将公式添加到新行中
  • @JohnnyCardel 这个纯代码选项可能会达到目的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-01
  • 2019-07-28
相关资源
最近更新 更多