Googleスプレッドシートの同じスプレッドシート内で、シートを複製する

GAS
目次

Googleスプレッドシートの同じスプレッドシート内で、シートを複製する操作は、毎月の集計シートを作成したり、特定の案件ごとにフォーマットを使い回したりする業務でよく発生する。画面の右クリック操作で行う「シートを複製」と同等の処理をGoogle Apps Scriptで行う場合、手動でのクリック操作を自動化できるため、月次の準備作業などを大幅に短縮できる。GAS 同一ファイル シート複製 と検索して調べると、さまざまな書き方が出てくるが、基本となるのは既存の Sheet オブジェクトを取得して copyTo メソッドを呼び出し、その直後に setName で名前を打ち替えるという流れだ。

しかし、スクリプト単体では数行で書ける処理であっても、実際の運用に組み込むと「指定した名前のシートが既に存在する」「複製後のシート名がデフォルトのまま残る」「ループ処理中に処理が追いつかず意図しない順序でシートが並ぶ」といった細かい不具合が発生しやすい。同じファイル内で完結する処理だからこそ、ファイルIDの指定ミスなどは起きにくい反面、既存シートとの競合や描画タイミングのズレがダイレクトにエラーとして表面化する。この記事では、同一ファイル内でのシート複製を安全に実行するための記述と、実務でハマりやすい挙動とその回避策について整理しておく。

スプレッドシート内でシートを複製する最小限のコード

まずは、最もシンプルに同一スプレッドシート内で指定したシートを複製し、新しい名前を設定するコードを示す。この処理は、決まったレイアウトの雛形シート(例:「テンプレ」)が存在し、それを複製して「2026-10」のような新しい名前を付けて運用したい時に使う。

const ss = SpreadsheetApp.getActiveSpreadsheet();
const copied = ss.getSheetByName("テンプレ").copyTo(ss);
copied.setName("2026-10");

このコードを実行した際、GASの内部では「テンプレ」シートの複製処理が走り、引数に指定された ss(つまり自分自身のスプレッドシート)の中に「テンプレ のコピー」という名前で一時的にシートが生成される。copyTo メソッドは複製された新しい Sheet オブジェクトを返すため、それを変数 copied で受け取り、そのまま setName("2026-10") を呼び出すことで、画面上に反映される名前を即座に書き換えている。

ここでずれる点として挙げられるのが、copyTo の処理と setName の処理の間に発生するタイムラグや、エラー時の状態だ。copyTo(ss) が実行された直後、スプレッドシート内部の構造としては一旦「テンプレ のコピー」というシートが追加されている。もし setName の段階で「2026-10」という名前が既に使われていた場合、GASは例外を投げてスクリプトをその場で停止させる。その結果、名前の書き換えが行われず、「テンプレ のコピー」という中途半端な名前のシートだけがファイル内に残ってしまう。

この現象を回避するためには、複製を実行する前に「2026-10」というシートが既に存在していないかを事前に確認するか、あるいは複製と名前変更を分離せず、後述するような名前チェックのガード節を挟んでから処理を呼び出す構成にする必要がある。単発の実行であれば手動で削除すれば済むが、定期実行のトリガーやフォーム回答に連動させた自動処理では、未処理のコピーシートが大量に増殖する原因になるため注意したい。

複製後のシート名重複で落ちる現象と命名の順序

Googleスプレッドシートの仕様上、1つのスプレッドシート内にまったく同じ名前のシートを複数存在させることはできない。画面操作で「テンプレ」を複製すると自動的に「テンプレ のコピー」「テンプレ のコピー (1)」といった連番が付くが、GASの setName メソッドで既存のシート名と重複する文字列を指定した場合は、自動で連番が付くことはなく、厳密にスクリプトエラー(Exception: 同名のシートがすでに存在します)となる。

実務で「Googleスプレッドシートの同じスプレッドシート内で、シートを複製する」処理を組み込む際、最も頻発する不具合がこの名前の重複だ。たとえば、毎月1日に実行されるスクリプトがあり、間違えて同日に2回実行してしまった場合や、事前にテストで同じ名前のシートを手動作成していた場合に、処理が途中で落ちてしまう。

これを防ぐためには、複製処理に入る前に対象の名前が存在するかどうかを判定するロジックが必須となる。具体的には ss.getSheetByName("2026-10") を呼び出し、戻り値が null でない場合は処理を中断するか、あるいは既存シートを削除・退避させてから複製を行うといった分岐を作成する。名前の確定を後回しにせず、複製処理を呼ぶ直前に「作成したい名前が空いているか」を判定することが、同一ファイル内での安全な運用の基本となる。

また、複製直後のシートの並び順についても意図とずれることがある。copyTo(ss) を実行すると、複製された新しいシートは通常、全シートの最も右側(一番最後)に追加される。雛形シートのすぐ隣に配置したい場合や、先頭に持ってきたい場合は、複製して名前を変えた後に ss.setActiveSheet(copied) や ss.moveActiveSheet(index) を組み合わせてシートの位置を明示的に指定する必要がある。単に複製して名前を変えるだけでは、シートの順序までは制御されない点を押さえておきたい。

ループ内で連続して複製する際に実行速度や順序がずれる理由

部署一覧やメンバー一覧の配列をもとに、同じスプレッドシート内で数十枚のシートを一気に複製するループ処理を書く場合、単発の実行時には起きなかった描画の遅延や順序の狂いが発生することがある。GASはスクリプトの実行とスプレッドシートの実際の画面描画・内部データの同期を非同期で効率化しているため、短時間に連続して copyTo と setName を繰り返すと、Googleサーバー側の処理が追いつかず、内部的な処理順序と見かけの順序がずれるケースが存在する。

たとえば、10個の拠点の名前が入った配列を forEach で回し、10枚のシートを連続生成する場合を考える。コード上は正しくループが回っていても、処理の途中で画面側の反映が遅れ、シートのインデックス番号が正しく割り当てられなかったり、最悪の場合はスクリプトのタイムアウト(6分制限)に引っかかることがある。同一ファイル内でのシート複製は、単なるセル値の書き換えと比べてスプレッドシート全体の構造を再構築する重い処理であるため、連続実行時には大きな負荷がかかる。

このような連続処理でのずれや遅延を回避するためには、ループ内で適宜 SpreadsheetApp.flush() を呼び出し、変更をその都度スプレッドシート側に確定させるか、あるいは一度に複製する枚数を制限する設計が有効だ。flush() を挟むことで、直前までに行われた copyTo や setName の状態がサーバー側で完全に評価された後に次のループへ進むため、「名前変更が適用される前に次の複製が走ってエラーになる」といったタイミング起因の不具合を大幅に減らすことができる。

ただし、flush() を多用しすぎると全体の実行時間が伸びるため、基本的には「1回の複製と名前変更が終わるごと」に呼び出す程度にとどめ、無駄なループを減らす工夫も求められる。処理対象が非常に多い場合は、一回のスクリプト実行ですべての複製を完了させようとせず、バッチ処理のように分割して実行する構成も検討すべきだ。

copyToメソッドでコピーされる要素と消える要素の境界線

同じスプレッドシート内でシートを複製する場合、手動でシートを複製した時と同様に、ほとんどの要素(値、数式、書式、条件付き書式、入力規則、結合セルなど)はそのまま新しいシートに引き継がれる。しかし、実務で高度な設定を行っているスプレッドシートにおいては、「複製されたはずなのに動かない」「設定が消えている」という落とし穴が存在する。

引き継がれるもののうち、特に注意が必要なのが「数式内のセル参照」だ。同一ファイル内でシートを複製した場合、数式内に書かれた別シートへの参照や、自シート内の相対参照はそのまま維持される。しかし、元シートの数式内で「テンプレ!A1」のように自分のシート名を直接指定した絶対記述を行っていた場合、複製後のシートにある数式も新しいシート名を指すのではなく、引き続き元の「テンプレ」シートのセルを参照し続けてしまう。複製後に「新しいシートの値を参照していると思ったのに、実は全部テンプレシートの数値を参照していた」という集計ミスは非常に多い。

一方、複製によって完全に引き継がれない、あるいは挙動が変わる要素もある。代表的なのが「シートの保護設定(アクセス権限)」や「図形描画に割り当てたボタンのスクリプト」だ。シート全体に保護をかけて特定ユーザーしか編集できないようにしていたとしても、copyTo で生成された新しいシートにはその保護設定が引き継がれず、誰でも編集可能な状態で生成されることが多い。複製後に保護が必要な業務プロセスであれば、GAS上で protect() メソッドを使って、複製処理のフローの中で再度保護を設定し直すコードを書かなければならない。

また、シート上に配置したボタン(図形描画)にスクリプト関数を割り当てていた場合、複製されたシート上のボタンを押しても関数が正しく発火しない、または元のシートを操作しようとしてしまうことがある。同一ファイル内での複製であっても、シート上のオブジェクトとスクリプトのバインド関係は崩れやすいため、ボタン操作を前提としたシートを動的複製する場合は、運用開始前に想定通り動作するかテストが必要となる。

複製失敗を防ぐための存在チェックと安全なシート作成手順

ここまでの課題を踏まえ、業務スクリプトとして実用に耐える「Googleスプレッドシートの同じスプレッドシート内で、シートを複製する」処理の安全な組み立て方を整理する。ただ複製コマンドを叩くだけではなく、前処理として「元となるテンプレシートが存在するか」「作成したい新しいシート名がすでに使われていないか」をチェックし、後処理として「名前の適用と確定」を行う堅牢な関数を作るのが標準的なやり方となる。

安全な手順としては、まず複製元となるシートオブジェクトを getSheetByName で取得し、それが null であれば「複製元のシートが見つかりません」として処理を安全に終了させる。次に、作成したい新しいシート名(例:「2026-10」)で同様に getSheetByName を実行し、すでにオブジェクトが取得できた場合は「同名シートが存在するため処理をスキップする」または「既存シートの名前を変更して退避させる」といった例外制御を行う。

二重のチェックを通過した段階で、初めて copyTo を実行する。そして戻り値として得られた新しいシートに対し setName を実行し、直後に SpreadsheetApp.flush() を呼び出して確定させる。この一連のステップを関数化しておくことで、自動処理の実行中にスクリプトが途中でエラー停止し、スプレッドシート上にゴミシートが残るリスクを最小限に抑えることができる。

スプレッドシート業務でGASを書く際、シートの複製は画面操作の延長として軽く考えられがちだが、実際には権限、参照、同名チェック、描画同期など多くの要素が絡む操作である。同一ファイル内での操作という閉じられた環境であっても、意図しない設定の抜け落ちや実行エラーを防ぐために、チェック処理を含めたロジックを組むことが安定した運用につながる。

タイトルとURLをコピーしました