目次
毎月の請求データや集計表の出力において、金額がゼロの行をそのまま残しておくと、印刷時やPDF化の際に不要な行が目立ってしまい、見栄えが悪くなることがあります。手動でフィルターをかけたり行を非表示にしたりすることも可能ですが、データの更新頻度が高い現場では、GASを活用して自動化するのが確実です。
金額ゼロの行をGASで非表示にする処理
const sheet = SpreadsheetApp.getActiveSheet();
const values = sheet.getRange("C2:C").getValues();
values.forEach((row, i) => {
if (row[0] === 0) sheet.hideRows(i + 2);
});
このコードは、C列の2行目から最終行までの値を配列として取得し、要素が0である場合に対応する行を非表示にします。「GAS ゼロ行 非表示」という処理を実装するにあたって、最も直感的で分かりやすい構成ですが、実際に運用に乗せる際にはいくつか注意すべき点が存在します。
まず、この処理をいつ使うかについてですが、主に集計完了後の「提出用シートの自動整形」や「帳票の自動生成プロセス」の最終段階で呼び出します。計算途中の段階で実行してしまうと、後続の関数が正しく参照できなくなったり、目視でのデータチェックが難しくなったりするためです。
次に、このコードをそのまま動かした際に「非表示にする位置がずれる」という問題が発生することがあります。その原因の多くは、参照しているデータの開始行と、配列のインデックスの対応関係を誤解していることにあります。例えば、ヘッダーが2行分あったり、途中に空行が挟まっていたりすると、非表示にしたい行の1行上や1行下が隠れてしまう事態に陥ります。
このようなズレを回避するためには、データ範囲の取得開始位置(上記コードでは C2)と、ループ内の行番号加算値(上記コードでは i + 2)の関係性を明確に理解し、シートのレイアウト変更に強い記述を意識することが重要です。
getValuesの配列インデックスと実際の行番号のズレ
GASでスプレッドシートを操作する際、最も頻繁に発生するトラブルの一つが、配列のインデックス(0始まり)とシートの行番号(1始まり)の不一致によるズレです。getValues メソッドで取得した2次元配列は、常にインデックス 0 から始まります。しかし、実際のシート上のデータは2行目から始まっていることが多く、このギャップを埋める計算を間違えると、意図しない行が非表示になってしまいます。
具体的な例で考えてみましょう。sheet.getRange(“C2:C”).getValues() を実行した場合、取得された配列 values の最初の要素である values[0] には、スプレッドシートの C2 セルの値が入っています。同様に values[1] には C3 セル、values[2] には C4 セルの値が入ります。
このとき、forEach のループ内で使われるインデックス i は、0, 1, 2 と増えていきます。もし sheet.hideRows(i) と書いてしまうと、i = 0 のときに「0行目」を隠そうとしてエラーになります。また、sheet.hideRows(i + 1) と書いた場合、i = 0 のときに「1行目(ヘッダー行)」が非表示になってしまい、肝心の金額ゼロの行(2行目)は表示されたままになってしまいます。
したがって、C2 から始まる範囲を取得した場合は、i + 2 というオフセットを指定しなければなりません。これは「配列の0番目は、シートの2行目である」というオフセット計算に基づいています。
実務においては、ヘッダーの行数が変更されたり、タイトル領域が追加されたりして、データの開始行が3行目や4行目に変更されるケースが多々あります。もしコード内に i + 2 のような数値を直接書いていると、レイアウト変更のたびにコードを修正しなければならず、修正漏れによるズレの原因になります。
この問題を回避するためには、データの開始行を変数として定義しておく手法が有効です。例えば const START_ROW = 2; と定数を定義し、sheet.hideRows(i + START_ROW) と記述することで、開始行が変更された場合でも定数の数値を1箇所修正するだけで対応できるようになります。さらに、getDataRange とヘッダー行数の差分から自動で計算する仕組みを作れば、より変更に強い処理を構築できます。
空欄セルや計算式が入った場合の比較挙動と判定の罠
金額がゼロの行を判定する際、単に row[0] === 0 という条件式を書くだけでは、意図しない結果を招くことがあります。スプレッドシート上では一見すると「0」に見えても、GASがデータを読み込んだときの型や値の内部表現によって、判定を通り過ぎてしまったり、逆に非表示にしたくない空欄行まで隠されてしまったりするためです。
まず注意すべきは、スプレッドシートの空欄セル(未入力のセル)です。JavaScriptにおいて、厳密な比較演算子 === を使用した場合、空欄セルから取得された空文字 “” と数値の 0 は等しくないと判断されるため、row[0] === 0 は false となり非表示になりません。しかし、もしゆるい比較演算子 == を使って row[0] == 0 と書いてしまった場合、JavaScriptの型変換ルールにより、空文字 “” や null が 0 と等しいとみなされ、データが入っていない空欄行まで全て非表示になってしまうという問題が生じます。
次に、セルに計算式が入っている場合です。計算式がエラーを返している場合や、計算結果として空文字 “” を出力している場合、getValues で取得される値は文字列やエラーオブジェクトになります。これらを適切にハンドリングしないと、比較時に予期せぬ挙動を示したり、処理が途中でストップしたりする危険があります。
また、表示形式の設定によって数値が「0」に見えているだけで、内部的には小数(例: 0.0001)が保持されているケースもあります。四捨五入の表示設定で「0」と表示されている行を隠したいのか、それとも厳密に値が 0 である行だけを隠したいのかによって、ロジックを使い分ける必要があります。
空欄を除外し、確実に数値の「0」だけを検出して非表示にするための回避策として、型チェックと値のチェックを組み合わせた条件判定を記述することが推奨されます。具体的には typeof row[0] === ‘number’ && row[0] === 0 のように、値が数値型(number)であり、かつ数値の0であることを明示的に確認する条件を入れるか、あるいは String(row[0]).trim() !== “” かつ Number(row[0]) === 0 のように文字列変換を挟んでチェックを行う方法があります。これにより、空欄セルや計算式による空文字を誤って非表示にしてしまうトラブルを防ぐことができます。
hideRowsをループ内で何度も呼ぶ際の処理速度低下と対策
冒頭で紹介したコードのように、forEach などのループ処理の中で毎回 sheet.hideRows() を実行する実装は、データ行数が少ない場合には問題なく動作します。しかし、データの行数が数百行、数千行と増えていくにつれて、処理にかかる時間が飛躍的に増大し、最終的にはGASの実行時間制限に達してタイムアウトエラーを引き起こす原因になります。
GASにおけるスプレッドシートAPIの呼び出し(SpreadsheetApp や Sheet オブジェクトのメソッド実行)は、非常にオーバーヘッドが大きい処理です。ループの回数分だけGoogleのサーバーに対して「行を非表示にする」という命令を1行ずつ送信することになるため、たとえば500行のデータのうち100行がゼロであった場合、100回のAPI呼び出しが発生します。これが処理速度を著しく低下させる最大の理由です。
この速度低下を回避し、「GAS ゼロ行 非表示」の処理を高速化するためには、APIの呼び出し回数を極限まで減らす設計が必要になります。具体的には、連続してゼロが並んでいる行を見つけ出し、単一の行を隠す hideRows(rowIndex) ではなく、開始行と行数を指定してまとめて隠す hideRows(rowIndex, numRows) を使用する方法が効果的です。
例えば、3行目から7行目までの5行分が連続して金額0である場合、ループ内で5回 hideRows を呼ぶのではなく、「3行目から5行分を非表示にする」という命令を1回だけ実行します。このように連続した範囲をまとめて処理することで、API呼び出し回数を大幅に削減できます。
さらにデータ量が膨大である場合は、1行ずつ非表示にするのではなく、スプレッドシートのフィルター機能をGASから操作して、0以外の値だけを表示するように条件付きフィルターを適用するアプローチや、非表示にするのではなく該当行を別のシートに転記して表示用データを作成するアプローチを検討するのも実務的にはスマートな解決策となります。
非表示にした行をshowRowsで一括再表示する実装
金額が0の行を自動で非表示にするスクリプトを運用する際、セットで考えておかなければならないのが「非表示にした行を元に戻す(再表示する)」処理です。データの更新や再集計が行われた際、以前の非表示状態が残ったままだと、新しく数値が入力された行が隠れたままになってしまい、集計結果の食い違いやデータの見落としといった深刻な業務ミスに繋がります。
行を再表示するためには、showRows メソッドを使用します。基本的な構文は hideRows と同様に sheet.showRows(startRow, numRows) であり、指定した開始行から指定した行数分の非表示状態を解除することができます。
実務での処理フローとしては、金額ゼロの行を探して非表示にする処理を実行する「直前」に、必ずシート全体の非表示状態を一旦リセット(全行再表示)するステップを組み込むのが鉄則です。こうすることで、常に最新のデータ状態に基づいて正しく非表示判定が行われるようになります。
具体的には、シートの最大行数を取得し、データが存在する全範囲に対して一括で showRows を実行します。
const maxRows = sheet.getMaxRows();
sheet.showRows(1, maxRows);
この処理を非表示ルーチンの先頭に追加しておくだけで、データが上書きされたり、過去に0だった行に数値が入り直したりした場合でも、古い非表示設定を引きずることなく、常に正確な画面表示を保つことが可能になります。
また、ユーザーが操作しやすいように、非表示用関数と再表示用関数を独立させて用意し、必要に応じて呼び出せるように設計しておく運用も現場では有効です。GASでの表示制御を行う際は、隠す処理だけでなく、必ず安全に元に戻せるルートを確保しておくことが、トラブルのない業務自動化を実現するための鍵となります。

