Google 試算表:刪除指定的單一欄 deleteColumn()

 


整理試算表最惱人的,往往不是公式,而是那些用不到、卻每天跟著你跑報表的多餘欄位。

這篇要帶你把 Google Apps Script 的 deleteColumn() 用順,用穩,也用得漂亮。從「什麼時候該刪欄、什麼時候只該清空或隱藏」開始,帶你認識欄位索引為何是 1 起算(A=1),為什麼大量刪除要「從右刪到左」才不會位移出包。

接著實作單欄刪除、連續多欄刪除、不連續欄合併刪、依標題黑白名單刪,以及自動偵測全空欄位的腳本。最後還會補上避雷:如何避免 #REF!、保護範圍與權限踩雷、以及超出欄數錯誤。

讀完你就能把表單回應、匯入資料、歷史欄位一次瘦身,報表更輕、效能也更順。希望本篇文章能夠幫助到需要的您。


目錄

{tocify} $title={目錄} 


deleteColumn() 是什麼?適用哪些情境

        deleteColumn() 是 Apps Script 的 Spreadsheet 服務中 Sheet 物件的成員方法,用來刪除指定位置的整個欄位(不是清空,是直接拿掉整欄)。常見應用像是:清理匯入資料的多餘欄、報表前置處理、移除隱私欄位、縮減欄數以避開 1,000 萬儲存格上限等。官方文件註明此方法存在於 Sheet 類別,另有 deleteColumns(start, howMany) 可一次刪除連續多欄。 

        索引從 1 開始(A 欄 = 1)。這點跟 JavaScript 陣列從 0 開始不同,寫腳本時務必分清楚。Google 的教學也特別提醒:處理列與欄時索引是 1-based。 

        另外,Google 試算表每個檔案最多 1,000 萬個儲存格,欄數上限為 18,278 欄(到 ZZZ 欄),刪掉不用的欄位可有效降載。 


快速開始:一步步跑起第一支刪欄腳本

1.    在欲處理的試算表中,點 擴充功能 → Apps Script。

2.    新增腳本,貼上下方範例,儲存。

3.    第一次執行會要求權限,依指示授權(需要 spreadsheets 編輯範圍)。 

範例 A:刪掉第一欄(A 欄)

function deleteCol_A() {
  const sheet = SpreadsheetApp.getActive().getActiveSheet();
  sheet.deleteColumn(1); // A 欄
}


說明:deleteColumn(columnPosition) 的參數是欄位位置(1 起算)。 


常用情境範例

範例 B:刪除第 N 欄(用數字定位)

function deleteCol_N(n) {
  const sh = SpreadsheetApp.getActive().getActiveSheet();
  sh.deleteColumn(n);
}
// 用法:deleteCol_N(5)  // 刪第 5 欄(E 欄)


寫防呆:可先用 getMaxColumns() 檢查 n 是否超界。 


範例 C:用「欄字母」刪除(把字母轉索引)

function letterToIndex(letter) {
  let idx = 0;
  for (const ch of letter.toUpperCase()) {
    idx = idx * 26 + (ch.charCodeAt(0) - 64); // 'A' -> 1
  }
  return idx;
}
function deleteColByLetter(letter) {
  const sh = SpreadsheetApp.getActive().getActiveSheet();
  sh.deleteColumn(letterToIndex(letter));
}
// deleteColByLetter('C') // 刪 C 欄


小心:欄索引是 1-based;陣列常是 0-based。 


範例 D:一次刪除「連續多欄」→ deleteColumns(start, howMany)

function deleteBlock(start, count) {
  const sh = SpreadsheetApp.getActive().getActiveSheet();
  sh.deleteColumns(start, count);
}
// deleteBlock(2, 3) // 刪掉 B~D 三欄


用 deleteColumns() 比逐欄 deleteColumn() 快,因為能 減少與試算表互動次數。 


範例 E:刪除「多個不連續欄」的最佳實務(從右往左 + 合併連續段)

function deleteNonAdjacentColumns(cols) {
  // cols: 欲刪的欄索引陣列(1-based),例如 [2,3,7,8,9,12]
  const sh = SpreadsheetApp.getActive().getActiveSheet();
  const sorted = [...cols].sort((a,b)=>a-b);
  // 先把連續索引合併成區段,再從「右到左」刪
  const blocks = [];
  let start = sorted[0], prev = sorted[0];
  for (let i=1;ib[0]-a[0]).forEach(([s,c]) => sh.deleteColumns(s, c));
}
// deleteNonAdjacentColumns([2,3,7,8,9,12])

為何「右到左」?因為刪掉左邊欄位會導致右邊尚未處理的索引改變,從右往左能避免位移問題。 


範例 F:依「欄標題」刪除或保留(黑白名單)

function deleteColumnsByHeader({
  sheetName = null,
  headerRow = 1,
  removeHeaders = [],     // 黑名單:遇到這些標題就刪
  keepHeaders = []        // 白名單:只保留這些,其餘全刪
} = {}) {
  const ss = SpreadsheetApp.getActive();
  const sh = sheetName ? ss.getSheetByName(sheetName) : ss.getActiveSheet();
  if (!sh) throw new Error('找不到指定工作表');

  const lastCol = sh.getLastColumn();
  if (lastCol === 0) return;

  const headers = sh.getRange(headerRow, 1, 1, lastCol).getValues()[0]
    .map(h => String(h).trim());

  let toDelete = [];
  if (keepHeaders.length) {
    const keep = new Set(keepHeaders);
    headers.forEach((h, i) => { if (!keep.has(h)) toDelete.push(i+1); });
  } else if (removeHeaders.length) {
    const ban = new Set(removeHeaders);
    headers.forEach((h, i) => { if (ban.has(h)) toDelete.push(i+1); });
  }
  if (toDelete.length) deleteNonAdjacentColumns(toDelete);
}
// 範例:只保留白名單欄位
// deleteColumnsByHeader({keepHeaders: ['日期','品名','金額']});


範例 G:刪除「全空」欄位

function deleteEmptyColumns() {
  const sh = SpreadsheetApp.getActive().getActiveSheet();
  const lastRow = sh.getLastRow();
  const lastCol = sh.getLastColumn();
  if (lastRow === 0 || lastCol === 0) return;

  const values = sh.getRange(1, 1, lastRow, lastCol).getValues();
  const toDelete = [];
  for (let c = 0; c < lastCol; c++) {
    let hasData = false;
    for (let r = 0; r < lastRow; r++) {
      const v = values[r][c];
      if (v !== '' && !(typeof v === 'string' && v.trim() === '')) { hasData = true; break; }
    }
    if (!hasData) toDelete.push(c + 1);
  }
  if (toDelete.length) deleteNonAdjacentColumns(toDelete);
}


範例 H:刪除「最後有內容欄」右側的所有欄(釋出配額)

function deleteColumnsRightOfLastContent() {
  const sh = SpreadsheetApp.getActive().getActiveSheet();
  const lastCol = sh.getLastColumn();
  const maxCol = sh.getMaxColumns();
  if (maxCol > lastCol) {
    sh.deleteColumns(lastCol + 1, maxCol - lastCol);
  }
}


getLastColumn() 取得最後一個「有內容」的欄;getMaxColumns() 取得工作表目前欄總數。 

刪掉冗餘欄可幫助避免觸碰 1,000 萬儲存格與 18,278 欄的限制。 


效能與大量刪除:怎麼刪得又快又穩

能用 deleteColumns() 就別迭代 deleteColumn():

        把相鄰欄合併成區段,單次呼叫刪除,可大幅減少與試算表的來回。 

從右往左刪:

        避免每刪一次就讓尚未處理的索引位移。 

極大量刪除(分散多段):

        改走 Advanced Sheets Service 的 spreadsheets.batchUpdate + DeleteDimensionRequest,能把多段刪除打包成一次 API 呼叫,速度與穩定度更好。 


Advanced Sheets 實戰範例(批次刪多段欄位)

/**
 * 先在「服務」中啟用 Advanced Google Services 的 Sheets API,
 * 並在雲端專案啟用 Sheets API。
 */
function batchDeleteColumnsByRanges(sheetId, ranges /* 陣列,如 [{start:1,end:3},{start:7,end:9}] */) {
  const requests = ranges.map(({start, end}) => ({
    deleteDimension: {
      range: {
        sheetId,
        dimension: 'COLUMNS',
        startIndex: start - 1, // API 是 0-based、左閉右開
        endIndex: end         // end 已是 1-based 轉 0-based 右開
      }
    }
  }));
  Sheets.Spreadsheets.batchUpdate({requests}, SpreadsheetApp.getActive().getId());
}


避雷清單:最常見錯誤 & 排除方式

1.    索引搞錯(拿 0 當 A 欄)

列欄方法一律 1-based(A=1),陣列才 0-based。寫換算時特別注意。 

2.    刪左邊導致索引位移

逐欄刪除請「右→左」;或先合併連續段再用 deleteColumns()。 

3.    #REF! 公式毀損

直接刪欄會讓依賴該欄的公式出現 #REF!。可在刪除前先「貼上為值」、或採用命名範圍、INDEX/MATCH、LET 等較不脆弱寫法。Google 社群亦說明刪除參照即會導致 #REF!。 

4.    受保護範圍/受保護工作表

非擁有者或無權限時,刪除會拋出例外。先檢查與移除保護,或要求權限。可透過 Apps Script 的 Protection 類別管理保護區域。 

5.    超出範圍(欲刪欄位 > 最大欄數)

在刪前先用 getMaxColumns() 驗證,避免「超界」錯誤。 

6.    大量刪除耗時

把多段刪除改成 Advanced Sheets 的 batchUpdate,單次請求完成。 

7.    表單回應工作表

刪除與表單題目對應的欄,可能使回應錯位。建議先在表單端調整或只刪非表單欄位。


與「清空/隱藏」的差別

刪除欄(deleteColumn/s):直接移除維度,公式參照會位移或壞掉。 

清空(clear() / clearContent()):資料變空,但欄仍在,參照結構較不受影響。

隱藏欄(hideColumns()):只是看不到,資料與參照都還在。 


穩健的實務流程建議

1.    先備份:複製分頁或用版本記錄回復點。

2.    先檢測:列出即將刪除的欄名與索引,讓你目視確認。

3.    先斷開敏感參照:報表頁先貼值、或改用命名範圍。

4.    右→左刪 + 區段化:減少位移與 API 呼叫次數。 

5.    大量刪除就批次 API:DeleteDimensionRequest 一次搞定。 


問題集

Q1:怎麼拿到某個工作表的 sheetId 給 Advanced Sheets 用?

A:SpreadsheetApp.getActive().getSheetByName('工作表').getSheetId() 即可。

Q2:刪欄會不會影響群組、篩選?

A:會按實際維度改變,群組與篩選的範圍也會隨之變動(建議先關閉或重新設定)。

Q3:我只想釋出檔案容量,不動參照,該用什麼?

A:優先考慮 clear() 或 hideColumns();真的要縮欄數才用 deleteColumn()。


張貼留言 (0)
較新的 較舊