簡體   English   中英

Google Apps 腳本 - 按列名而不是硬編碼范圍比較兩張表的更改

[英]Google Apps Script - Compare two sheets for changes by column names instead of hardcoded ranges

我有兩張紙,“進口”和“案例”。

在“導入”表中,我從有時有更多列或現有列每次以不同方式排列的外部源導入數據。 在此處輸入圖像描述

在“案例”表中,這是我存儲上周所有導入數據的每周快照的地方,我添加了包含更多信息的附加列,例如評論、后續步驟等。 在此處輸入圖像描述

我正在尋找一種方法來比較兩個工作表而不對任何列范圍進行硬編碼。 我認為最有效的方法是在兩張表中查找列 header 名稱,然后檢查參考“案例編號”行的更改。 如果您能想到更好的方法,請告訴我。

我已經設法編寫了一個代碼來查看標題並識別特定列名“案例編號”的索引號。 此列將始終出現在兩個工作表中,它可以作為應該驗證的行的參考點,但它可能是每張工作表的不同行。 我將需要同時遍歷 CASES 表中的所有列標題並檢查 IMPORT 表中的更新。

我只需要檢查/循環 CASES 表中幾個特定列的更改。 列名稱,例如:聯系人姓名、職務、優先級、狀態。

我的目標是實現 3 個可能的結果:

  1. [ 已完成 ]案例表中的“案例編號”在導入表中未找到 - 這意味着該案例自上周以來已關閉。 行動:在案例表中將整行突出顯示為灰色(這將表明案例不再打開,應在確認后從列表中刪除)。 在此處輸入圖像描述

  1. 導入表中的“案例編號”在案例表中未找到 - 這意味着案例是新的,需要添加到底部的案例表中。 行動:將數據從 IMPORT 表復制到 CASES 表,並將其粘貼到底部的正確列中,並將整行突出顯示為綠色,以指示新的數據條目。 對於 IMPORT 表中的 CASES 表中所有不存在的列,應跳過這些列。 在此處輸入圖像描述

  1. CASES表中找到 IMPORT 表中的“Case Number” - 對於匹配的 Case Number 記錄,我需要驗證自上周以來任何 CASES 表列中是否有任何更改。 行動:如果在任何單元格中發現更改,請使用 CASES 表中的新數據更新單元格,並將單元格背景顏色更改為黃色以突出顯示已更新的單元格。 對於沒有變化的單元格,跳過。 在此處輸入圖像描述

對於冗長的問題陳述,我深表歉意。

我是 JS 和 GAS 的新手,我寫這篇文章是希望一些 JavaScript 專家能理解我的想法並建議可能更簡單的方法來完成我的項目。

目前,我一直在尋找一種正確的方法來循環遍歷 Header 名稱,然后檢查 IMPORT 表中的單元格值,並根據 Case Name 值/行將其與 CASES 表進行比較。

  • 結果 1 - 完成
  • 成果 2 - 進行中
  • 結果 3 - 待定...

我會繼續更新這個話題,展示這個項目的最新進展。 到目前為止,我在 Internet 上找到的所有示例都是基於單元格和列的硬編碼范圍。 我認為我的方法很有趣,因為它為數據集提供了面向未來的靈活性。

請讓我知道您的想法或想法,以獲得更直接的方法:)

鏈接到實時工作表

更新代碼:

// Create Top Menu
function onOpen() {
  let ui = SpreadsheetApp.getUi();
  ui.createMenu('>> REPORTS <<').
  addItem('Highlight Closed Cases', 'closedCases').
  addItem('Check for new Cases', 'addCases').addToUi();
}

// IN PROGRESS (Outcome 2) - Add and highlight new cases in CASES sheet
function addCases() {

  let ss = SpreadsheetApp.getActiveSpreadsheet();

  // Get column index number for Case Number
  let activeImportCol = getColumnIndex("Case Number", "IMPORT");
  let activeCasesCol = getColumnIndex("Case Number", "CASES");

  let importHeaders = loadHeaderNames("IMPORT");
  let casesHeaders = loadHeaderNames("CASES");

  // Load Case Number columns values into array
  let loadImportValues = getColumnValues("Case Number", "IMPORT");
  let loadCasesValues = getColumnValues("Case Number", "CASES");
  // Convert to 1D array
  let newImportValues = loadImportValues.map(function (row) { return row[0]; });
  let newCasesValues = loadCasesValues.map(function (row) { return row[0]; });

  // Get number of columns
  var numImportCol = ss.getSheetByName("IMPORT").getLastColumn();

  // Loop through IMPORT sheet "Case Number" column to find new Case Numbers - execute OUTCOME 3 or 2
  for (var line in newImportValues) {
    var isMatched = newCasesValues.indexOf(newImportValues[line]);
    if (isMatched !== -1) {
      

      // "Case Number" from the IMPORT sheet WAS FOUND in the CASES sheet - EXECUTE OUTCOME 3
      // ****************************************************************************************
      // For the matching Case Number records, I need to validate if there were any changes in any CASES sheet columns since last week
      // Action: If a change was found in any of the cells, update the cell with new data in CASES sheet 
      // and change the cell background colour to yellow to highlight the cell was updated. For cells without changes, skip.

      
    } else {
      
      // "Case Number" from the IMPORT sheet was NOT FOUND in the CASES sheet - EXECUTE OUTCOME 2
      // ****************************************************************************************
      // Copy the new data row from the IMPORT sheet to the CASES sheet and paste it in the correct columns 
      // at the bottom and highlight the entire row as green to indicate a new data entry.
      // For all non-existing/not matching column names in the CASES sheet that are not in IMPORT sheet, those should be skipped.
      
    }
  }
}

// COMPLETED (Outcome 1) - Highlight entire row grey for missing values in CASES sheet
function closedCases() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();

  // Load all Casen Number columns values into array
  var importValues = getColumnValues("Case Number", "IMPORT");
  var casesValues = getColumnValues("Case Number", "CASES");

  // Convert to 1D array
  var newImportValues = importValues.map(function (row) { return row[0]; });
  var newCasesValues = casesValues.map(function (row) { return row[0]; });

  // Get column index number for Case Number
  var activeCol = getColumnIndex("Case Number", "CASES");

  // Get number of columns
  var numCol = ss.getSheetByName("CASES").getLastColumn();

  // Loop though CASES "Case Number" column and highlight closed cases (not found in IMPORT tab)
  for (var line in newCasesValues) {
    var isMatched = newImportValues.indexOf(newCasesValues[line]);
    if (isMatched !== -1) {

      // If found then...
      ss.getSheetByName("CASES").getRange(+line + 2, 1, 1, numCol).setBackground(null);

    } else {
      // Higlight row with missing cases - grey
      ss.getSheetByName("CASES").getRange(+line + 2, 1, 1, numCol).setBackground("#d9d9d9");
    };
  }
}

// Load column values
function getColumnValues(label, sheetName) {

  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);

  // Get column number for Case Number
  var colIndex = getColumnIndex(label, sheetName);

  // Get number of rows in Case Number
  var numRows = ss.getLastRow() - 1;

  // Load Case Number values into array
  var colValues = ss.getRange(2, colIndex, numRows, 1).getValues();

  return colValues;

}

// Load column header names
function loadHeaderNames(sheetName) {

  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);

  let HeaderArray = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
  let colidx = {};
  HeaderArray.forEach((h, i) => colidx[h] = i);

  return HeaderArray;

}

// Get column name index value
function getColumnIndex(label, sheetName) {

  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);

  // Find last column
  var lc = ss.getLastColumn();

  // Load headers into array
  var lookupRangeValues = ss.getRange(1, 1, 1, lc).getValues()[0];

  // Search for label and return the column number
  var index = lookupRangeValues.indexOf(label) + 1;

  return index;

}

使所有這些處理更容易的一種方法是重新排序列,以便它們始終位於同一個位置,如下所示:

=arrayformula( 
  iferror( 
    vlookup( 
      hlookup("Case Number"; IMPORT!A1:G; row(IMPORT!A2:G); false); 
      { 
        hlookup("Case Number"; IMPORT!A1:G; row(IMPORT!A1:G); false) \ 
        IMPORT!A1:G 
      }; 
      match(IMPORT!A1:G1; CASES!A1:G1; 0) + 1; 
      false 
    ) 
  ) 
)

該公式將對IMPORT中的列重新排序,以便這些列的順序與它們在CASES:A1:G1中列出的順序相同。

然后,您可以使用更多的公式或腳本函數來處理數據,確信特定類型的數據將始終位於同一列中。 例如,您可以使用以下內容列出已關閉的案例:

=filter( 'CASES normalized':A2;G: isna(match('CASES normalized';C2:C; 'IMPORT normalized'!C2:C; 0)) )

...並像這樣打開案例:

=filter( 'CASES normalized':A2;G: match('CASES normalized';C2:C; 'IMPORT normalized'!C2:C; 0) )

請參閱您的示例電子表格

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM