如果你也覺得試算表越整理越亂,八成是卡在「刪除」這一步沒用對方法。
這篇用日常語氣把 deleteRow() 講透:它在什麼時候出場最好、怎麼寫才不會越刪越慢、為什麼大家都說要「從下往上」刪。內容包含五個實戰範例:單列刪除、連續多列、尾端空白列整理、依欄位值條件刪、判斷顯示為空的列。
每個段落都有注意事項與小提醒,像是避免誤傷表頭、遇到保護範圍怎麼辦、以及配額和時間限制的基本概念。讀完之後,你會多一把順手的清理刀,報表維護也能省下不少時間。希望本篇文章能幫助到需要的您。
目錄
{tocify} $title={目錄}
為什麼要學 deleteRow()?
在自動化清理資料、移除過期列、刪除空白或不合規紀錄時,直接用 Apps Script 刪列最省事。Sheet.deleteRow(rowPosition) 能刪除指定的單一列;若要批次刪好幾列,還有 deleteRows(rowPosition, howMany) 可一次處理連續區塊。兩者皆屬於 Spreadsheet Sheet 類別的方法。
基本觀念與語法
座標從 1 開始:Apps Script 的列、欄索引皆以 1 為起點(第 1 列、第 1 欄)。
deleteRow(row):刪除指定列,並向上位移下方所有列。
deleteRows(row, howMany):自 row 起連續刪除 howMany 列。
搭配常用偵測方法
getLastRow():最後一列「有內容」的位置。
getMaxRows():工作表目前擁有的總列數(可能比實際資料多)。
官方 Sheet 類別文件同時列出 deleteRow() / deleteRows()、getLastRow() / getMaxRows() 的定義與回傳值說明。
實作前準備
1. 開啟試算表 → 功能表「擴充功能 → Apps Script」開啟編輯器。
2. 在專案中新增 .gs 檔,貼上本文範例程式。
3. 第一次執行會跳出授權畫面,依指示授權腳本存取該試算表。
4. 回到試算表,可把程式綁定自訂選單或按鈕,方便日常使用。
這些操作依 2025 年介面說法整理;刪列的底層能力仍以 Spreadsheet 服務為準。
快速上手:5 個「最常用」情境範例
刪除單一指定列
function deleteOneRow() {
const sheet = SpreadsheetApp.getActiveSheet();
sheet.deleteRow(5); // 刪除第 5 列
}
適合與 UI 事件搭配(例如點選某列後執行)。
刪除連續的多列(用 deleteRows)
function deleteBlock() {
const sheet = SpreadsheetApp.getActiveSheet();
const start = 10; // 從第 10 列開始
const howMany = 5; // 刪 5 列 → 10~14 列
sheet.deleteRows(start, howMany);
}
一次刪一個區段,比迴圈逐列 deleteRow 快很多。
刪除「尾端多餘空白列」
許多表單或匯入流程會留下超多空列,可用 getLastRow() + getMaxRows() 精準縮減。
function trimTrailingEmptyRows() {
const sh = SpreadsheetApp.getActiveSheet();
const last = sh.getLastRow();
const max = sh.getMaxRows();
if (max > last) {
sh.deleteRows(last + 1, max - last);
}
}
這是社群長年沿用的模式,原理正是以「真實最後列」對齊「目前最大列」做收尾。
依「欄位值」刪除資料列(例如狀態=已關閉)
重點:先把資料一次讀入陣列,再決定要刪哪些列,最後由下往上批次刪除(避免位移問題)。
function deleteRowsByValue() {
const sh = SpreadsheetApp.getActiveSheet();
const header = 1; // 表頭列數
const keyCol = 3; // 目標欄(例:第 3 欄是狀態)
const target = '已關閉'; // 刪除此狀態的列
const lastRow = sh.getLastRow();
if (lastRow <= header) return;
const values = sh.getRange(header + 1, keyCol, lastRow - header, 1).getValues().flat();
const toDelete = [];
values.forEach((v, i) => { if (v === target) toDelete.push(i + header + 1); });
deleteInBatches_(sh, toDelete);
}
// 將不連續列壓成「連續區塊」後,再 bottom-up 刪除
function deleteInBatches_(sheet, rowIndexes) {
if (!rowIndexes.length) return;
rowIndexes.sort((a, b) => a - b);
const blocks = [];
let start = rowIndexes[0], prev = start;
for (let i = 1; i < rowIndexes.length; i++) {
const cur = rowIndexes[i];
if (cur === prev + 1) {
prev = cur;
} else {
blocks.push([start, prev - start + 1]);
start = prev = cur;
}
}
blocks.push([start, prev - start + 1]);
// 由下往上刪,避免索引位移
for (let i = blocks.length - 1; i >= 0; i--) {
const [row, count] = blocks[i];
sheet.deleteRows(row, count);
}
}
先批次讀寫、再成塊刪除,符合 Apps Script 官方「批次操作」最佳實務。
刪空白列(含公式回傳 "" 的列)
若希望把「看起來空白」的列通通移除,建議用 getDisplayValues() 來判斷。
function deleteEmptyDisplayRows() {
const sh = SpreadsheetApp.getActiveSheet();
const header = 1;
const lastRow = sh.getLastRow();
const lastCol = sh.getLastColumn();
if (lastRow <= header) return;
const values = sh.getRange(header + 1, 1, lastRow - header, lastCol).getDisplayValues();
const toDelete = [];
values.forEach((row, i) => {
const joined = row.join('').trim();
if (joined === '') toDelete.push(i + header + 1);
});
deleteInBatches_(sh, toDelete);
}
getDisplayValues() 會以顯示結果判斷空白,更貼近使用者觀感。
效能與穩定度:把時間花在對的地方
1. 一次讀寫、多筆處理
避免在迴圈中頻繁呼叫 deleteRow();盡量用 deleteRows() 成批處理。這是 Apps Script 官方建議的「批次操作」做法。
2. 由下往上刪
刪除會改變後續列的索引;從底部開始可避免位移造成的錯刪。
3. 合併區塊
先把要刪的列整理成「連續區塊」,每塊只呼叫一次 deleteRows(),明顯提速。(上面 deleteInBatches_ 已示範)
4. 批量刪除的另一條路:Sheets API
若你需要在跨試算表或大量分散的列上刪除,亦可改用 Google Sheets API batchUpdate 的 DeleteDimensionRequest。Apps Script 內可啟用 Advanced Service 或使用外部憑證;這條路適合「一次組裝許多刪除請求」再送出。
權限與保護範圍(你能刪的,程式才刪得動)
列若落在受保護的範圍或工作表受保護,且目前執行者沒有權限,刪除會拋出例外。
相關權限判斷、移除保護等可用 Protection 類別處理;必要時以擁有者身分(如 Web App / 安裝觸發器)執行。
風險控管:Undo 與版本記錄
可否 Undo? Google 在新版 Sheets 的釋出說明中提到:Undo 能回復由腳本造成的變更;但實務上若一次做了很多步驟,有時需要多次 Undo 才能回到原狀。因此大規模刪除前,仍建議先備份或用版本記錄。
版本記錄:從「檔案 → 版本記錄 → 檢視版本記錄」可回到任一早期版本,是最保險的後悔藥。
常見錯誤與雷點
1. 用 deleteRow() 逐列往上刪,結果「跳刪」
原因:刪除會位移索引。
對策:改成自底向上,或先壓成連續區塊用 deleteRows() 一次刪。
2. 把表頭也刪掉
原因:條件篩選時忘了跳過第 1 列(或多列表頭)。
對策:取值時從 header + 1 開始。
3. 看起來空白但刪不掉
原因:儲存格含公式,顯示為空字串 ""。
對策:使用 getDisplayValues() 判斷空白(見上方範例)。
4. 刪列很慢
原因:在迴圈裡多次呼叫 deleteRow(),反覆觸發與雲端通訊。
對策:一次讀取 → 彙總目標 → deleteRows() 成批刪;必要時考慮 Sheets API batchUpdate。
5. 受到保護範圍阻擋
原因:無權修改受保護的範圍/工作表。
對策:檢查 Protection 物件,或改以擁有者身分執行(Web App / 安裝觸發器)。
6. 超過執行時間限制(常見於大量刪除)
Apps Script 單次執行有時間與配額限制;遇到大檔可能中途停止。
對策:切分工作、批次化、或改用時間驅動觸發器分段跑。
進階:安全的刪除流程(確認視窗/試跑模式)
為避免誤刪,可在執行前顯示確認對話框,或先列出將被刪除的列數量(試跑)。
function confirmAndDeleteByStatus() {
const ui = SpreadsheetApp.getUi();
const resp = ui.alert('刪除確認', '即將刪除狀態=已關閉 的資料列,是否繼續?', ui.ButtonSet.YES_NO);
if (resp !== ui.Button.YES) return;
deleteRowsByValue(); // 呼叫前述的刪除函式
}
