- クラウドサービス
GASスプレッドシート操作入門|getRange・setValues・最終行
GAS(Google Apps Script)でスプレッドシートを操作するときは、「ブック → シート → 範囲 → 値」の順にたどり、値は2次元配列でまとめて読み書きするのが基本です。 この流れと、範囲を指定する getRange、値を書き込む setValues、最終行の求め方の3つを押さえれば、集計や転記の自動化はほとんど書けるようになります。
この記事では、読み取りと書き込みの両方を1ページで通し、getRange の4つの引数パターン、5つの読み書きメソッドの使い分け、最終行の取得3通りの違い、範囲と配列の大きさが合わないときの直し方、セルを1つずつ書く処理を一括書き込みに直す前後のコードまでをまとめます。コードは V8 ランタイムの書き方(const、アロー関数、分割代入、テンプレートリテラル)でそろえています。
確認環境:メソッド名・引数・戻り値は、Google 公式の Apps Script リファレンス(Spreadsheet サービス)と、型定義パッケージ @types/google-apps-script 2.0.13 の記載に合わせています。コードの構文と配列の処理は、Node.js 22 の上で、シートを2次元配列でまねた簡易モックを使って動かしました。記事中の「モックでの出力」はその結果で、配列は JSON 形式で表示しています。
GASスプレッドシート操作の早見表
| 段階 | やりたいこと | 書き方 | 戻り値 |
|---|---|---|---|
| ブック | スクリプトをひも付けたブックを取る | SpreadsheetApp.getActiveSpreadsheet() |
Spreadsheet |
| ブック | ID を指定して別のブックを開く | SpreadsheetApp.openById(id) |
Spreadsheet |
| シート | 名前でシートを取る | ss.getSheetByName('注文') |
Sheet(無ければ null) |
| シート | すべてのシートを取る | ss.getSheets() |
Sheet の配列 |
| 範囲 | セル1つ | sheet.getRange(2, 3) |
Range |
| 範囲 | 縦に何行か | sheet.getRange(2, 3, 5) |
Range |
| 範囲 | 行数×列数の四角形 | sheet.getRange(2, 3, 5, 2) |
Range |
| 範囲 | A1形式で指定 | sheet.getRange('C2:D6') |
Range |
| 範囲 | データのある範囲すべて | sheet.getDataRange() |
Range |
| 値を読む | セル1つの値 | range.getValue() |
値1つ |
| 値を読む | 範囲の値をまとめて | range.getValues() |
2次元配列 |
| 値を書く | セル1つに書く | range.setValue(値) |
Range |
| 値を書く | 範囲にまとめて書く | range.setValues(2次元配列) |
Range |
| 値を書く | データの最後に1行足す | sheet.appendRow(1次元配列) |
Sheet |
| 最終行 | 内容のある最後の行番号 | sheet.getLastRow() |
整数 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「GASスプレッドシート操作入門|getRange・setValues・最終行」
準備:スクリプトを開く場所とサンプルの表
スプレッドシートを開き、メニューの「拡張機能」→「Apps Script」を選ぶと、そのブックにひも付いたスクリプト(コンテナバインドスクリプト)のエディタが開きます。ひも付いたスクリプトでは、getActiveSpreadsheet() を使うとブックの ID を書かずに親のブックを取得できます(Google 公式ガイド「Container-bound Scripts」)。
この記事のコードは、シート名「注文」の次の表を前提にしています。7行目は空白行で、8行目の H列にだけメモが入っています。この「表から離れた場所の入力」が、あとで最終行の違いを比べるときの材料になります。
| 行 | A 注文ID | B 商品 | C 数量 | D 単価 | E 金額 | F 備考 | G | H |
|---|---|---|---|---|---|---|---|---|
| 1 | 注文ID | 商品 | 数量 | 単価 | 金額 | 備考 | ||
| 2 | A-001 | ノート | 10 | 120 | ||||
| 3 | A-002 | ペン | 25 | 80 | 急ぎ | |||
| 4 | A-003 | ファイル | 8 | 300 | ||||
| 5 | A-004 | マウス | 3 | 1500 | ||||
| 6 | A-005 | キーボード | 2 | 4800 | ||||
| 7 | ||||||||
| 8 | 合計は別シート |
シートのセルA1に貼り付けるためのタブ区切りデータです(H8 のメモは手で入力してください)。
注文ID 商品 数量 単価 金額 備考
A-001 ノート 10 120
A-002 ペン 25 80 急ぎ
A-003 ファイル 8 300
A-004 マウス 3 1500
A-005 キーボード 2 4800
全体像:ブック→シート→範囲→値の順にたどる
function readBasics() {
const ss = SpreadsheetApp.getActiveSpreadsheet(); // ブック
const sheet = ss.getSheetByName('注文'); // シート
if (sheet === null) {
throw new Error('シート「注文」が見つかりません');
}
const range = sheet.getRange(2, 1, 5, 4); // 範囲(A2 から 5行×4列)
const values = range.getValues(); // 値(2次元配列)
Logger.log(range.getA1Notation());
Logger.log(values.length + '行 × ' + values[0].length + '列');
Logger.log(values[0]);
Logger.log(values[0][1]);
}
モックでの出力:
A2:D6
5行 × 4列
["A-001","ノート",10,120]
ノート
getValues()の戻り値は「行の配列」の配列です。values[0]が範囲の1行目、values[0][1]がその2列目です。- 配列の番号は 0 から、シートの行番号・列番号は 1 から始まります。「配列の i 番目はシートの i+1 行目」というずれが、GAS でいちばん多いつまずきどころです。
getSheetByNameは、その名前のシートが無いと null を返します(型定義では戻り値がSheet | null)。シート名の打ちまちがいにすぐ気づけるよう、null の判定を最初に入れるのがおすすめです。
getRangeの4つの引数パターン
Sheet の getRange には、引数の数と種類で4つの呼び方があります。
| 呼び方 | 引数の意味 | 例 | 指す範囲 |
|---|---|---|---|
getRange(row, column) |
行番号、列番号 | getRange(2, 3) |
C2 の1セル |
getRange(row, column, numRows) |
行番号、列番号、行数 | getRange(2, 3, 5) |
C2:C6(縦に5行) |
getRange(row, column, numRows, numColumns) |
行番号、列番号、行数、列数 | getRange(2, 3, 5, 2) |
C2:D6(5行×2列) |
getRange(a1Notation) |
A1形式の文字列 | getRange('C2:D6') |
C2:D6 |
function getRangePatterns() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
const a = sheet.getRange(2, 3); // 行, 列
const b = sheet.getRange(2, 3, 5); // 行, 列, 行数
const c = sheet.getRange(2, 3, 5, 2); // 行, 列, 行数, 列数
const d = sheet.getRange('C2:D6'); // A1形式の文字列
for (const r of [a, b, c, d]) {
Logger.log(`${r.getA1Notation()} : ${r.getNumRows()}行 × ${r.getNumColumns()}列`);
}
}
モックでの出力:
C2 : 1行 × 1列
C2:C6 : 5行 × 1列
C2:D6 : 5行 × 2列
C2:D6 : 5行 × 2列
| つまずきやすい点 | 正しい考え方 |
|---|---|
| 3つ目・4つ目の引数を「終わりの行・列」と思ってしまう | 3つ目は行数、4つ目は列数。C2 から C6 までなら getRange(2, 3, 5)(6 ではなく 5) |
| 引数の順番を「列、行」にしてしまう | 行が先、列が後。A1形式の「C2」(列→行)とは逆 |
列を文字で渡してしまう(getRange(2, 'C')) |
数値で渡す。C列は 3 |
| 最終行まで取りたい | 行数を計算する。2行目から最終行までは lastRow - 1 行 |
ループや計算で位置が変わるなら数値の引数、決まった場所ならA1形式と使い分けると読みやすくなります。
getValue・getValues・setValue・setValues・appendRowの使い分け
| メソッド | 向き | 対象 | 受け渡しする形 | 使いどころ |
|---|---|---|---|---|
getValue() |
読む | 範囲の左上の1セル | 値1つ(数値・真偽値・日付・文字列) | 設定値など、決まったセルを1つだけ読む |
getValues() |
読む | 範囲全体 | 2次元配列 | 表をまとめて読む。基本はこちら |
setValue(value) |
書く | セル1つ | 値1つ | 見出しや日付など、1セルだけ書く |
setValues(values) |
書く | 範囲全体 | 2次元配列(範囲と同じ行数×列数) | 表をまとめて書く。基本はこちら |
appendRow(rowContents) |
書く | シートのデータの下 | 1次元配列(1行ぶん) | 記録を1件ずつ足していく |
読む:getValue と getValues の戻り値の形
function valueAndValues() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
Logger.log(sheet.getRange('B2').getValue()); // セル1つ → 値そのもの
Logger.log(sheet.getRange('B2').getValues()); // セル1つ → [[値]]
Logger.log(sheet.getRange('B2:B4').getValues()); // 縦3セル → [[値],[値],[値]]
Logger.log(sheet.getRange('A2:C2').getValues()); // 横3セル → [[値,値,値]]
Logger.log(sheet.getRange('B2:B4').getValue()); // 複数セルに getValue → 左上の1つだけ
Logger.log(sheet.getRange('E2').getValue() === ''); // 空のセルは空文字
}
モックでの出力:
ノート
[["ノート"]]
[["ノート"],["ペン"],["ファイル"]]
[["A-001","ノート",10]]
ノート
true
- セルが1つでも、
getValues()は必ず2次元配列([[値]])を返します。 - 縦1列は
[[a],[b],[c]]、横1行は[[a,b,c]]です。この2つの形の違いを覚えておくと、書き込みのときに迷いません。 - 複数セルの範囲に
getValue()を使うと、左上の1セルの値だけが返ります。 - 空のセルは空文字(
'')として返ります。
書く:setValue・setValues・appendRow
function writeBasics() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
// セル1つに書く
sheet.getRange('J1').setValue('確認日');
// 範囲にまとめて書く(2行×2列の範囲に、2行×2列の配列)
sheet.getRange(2, 10, 2, 2).setValues([
['2026/10/05', '済'],
['2026/10/05', '済'],
]);
// データの最後に1行足す
sheet.appendRow(['A-006', 'ファイル', 8, 300]);
}
モックでの出力(書き込み後に J1:K3 と、追加された行を読み直した結果):
J1:K3 = [["確認日",""],["2026/10/05","済"],["2026/10/05","済"]]
追加された行 = 9 [["A-006","ファイル",8,300]]
appendRow で足した行は、表のすぐ下の7行目ではなく 9行目に入りました。appendRow は「シートの現在のデータ領域のいちばん下」に行を足すメソッドで、このシートでは H8 のメモが内容のある最後の行だからです。表の下に続けて書きたいときは、あとで紹介する「特定の列の最終行」を使って書き込み位置を決めます。
最終行を取得する3通りと違い
function lastRowThreeWays() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
// 1) getLastRow:シート全体で、内容のある最後の行
const byLastRow = sheet.getLastRow();
// 2) getDataRange:データのある範囲をまるごと取り、その行数を数える
const byDataRange = sheet.getDataRange().getNumRows();
// 3) 特定の列だけの最終行:列を配列で読み、下から最初の空でないセルを探す
const byColumnC = lastRowInColumn(sheet, 3); // C列(数量)
const byColumnF = lastRowInColumn(sheet, 6); // F列(備考)
Logger.log(`getLastRow: ${byLastRow}`);
Logger.log(`getDataRange: ${byDataRange}`);
Logger.log(`C列の最終行: ${byColumnC}`);
Logger.log(`F列の最終行: ${byColumnF}`);
}
/**
* 指定した列で、値が入っている最後の行番号を返す。
* 途中に空白セルがあっても、いちばん下の入力済みセルを見つける。
* 列がすべて空なら 0 を返す。
*/
function lastRowInColumn(sheet, column) {
const lastRow = sheet.getLastRow();
if (lastRow === 0) return 0;
const values = sheet.getRange(1, column, lastRow, 1).getValues();
for (let i = values.length - 1; i >= 0; i--) {
if (values[i][0] !== '') return i + 1; // 配列は0始まり、行番号は1始まり
}
return 0;
}
モックでの出力:
getLastRow: 8
getDataRange: 8
C列の最終行: 6
F列の最終行: 3
| 方法 | 何を数えるか | サンプル表での結果 | 向いている場面 |
|---|---|---|---|
sheet.getLastRow() |
シート全体で、内容のある最後の行の位置 | 8 | シートに表が1つだけあり、ほかの場所に入力がない |
sheet.getDataRange().getNumRows() |
データのある範囲の行数 | 8 | 表全体を getValues() でまとめて読むついでに行数も知りたい |
lastRowInColumn(sheet, 列番号) |
指定した列で値が入っている最後の行 | C列は 6、F列は 3 | 表の外にメモや集計がある。列によって入力のある行が違う |
getLastRow()とgetDataRange()は、シートのどこかに入力があればその行まで数えます。表から離れたメモ、消し忘れた値、ほかの人が足した行があると、思ったより大きな数になります。- 「A列の注文IDが入っている最後の行」のように基準にする列を1つ決めて数えると、表の外の入力に左右されません。
lastRowInColumnは列を1回のgetValues()で読み、配列を下からたどるので、F列のように途中に空白セルがある列でも、いちばん下の入力済みセル(3行目)を返します。 getDataRange()で取った範囲を使うと、空白行(7行目)やメモの行(8行目)も配列に入ります。集計に使う前に、filterで必要な行だけに絞ると安心です(後半の V8 構文のコードで使っています)。
Range には getNextDataCell(direction) というメソッドもあります。公式リファレンスの説明は「指定した方向にある、値の入った連続したセルのかたまりの端のセルを返す」です。方向は SpreadsheetApp.Direction.UP・DOWN・PREVIOUS・NEXT で指定します。途中に空白セルがある列では「かたまりの端」が途中のセルになることがあるため、空白をまたいで最終行を知りたいときは、上の lastRowInColumn のように配列で調べる方法が確実です。
範囲と配列の行数・列数が合わないときの直し方
setValues は「範囲に対して、四角形に並んだ値を設定する」メソッドで、渡す2次元配列の大きさは範囲の大きさと一致している必要があります(公式リファレンスの記載)。合わない形の配列は書き込めないので、書き込む前に自分で確かめる関数を用意しておくと、どこが合っていないかを日本語ですぐ確認できます。
/**
* 範囲と配列の行数・列数が合っているかを書き込み前に確かめる。
*/
function assertSameSize(range, values) {
const rows = range.getNumRows();
const cols = range.getNumColumns();
if (!Array.isArray(values) || !values.every(Array.isArray)) {
throw new Error('値は2次元配列(配列の配列)で渡してください');
}
if (values.length !== rows) {
throw new Error(`行数が合いません:範囲は${rows}行、配列は${values.length}行`);
}
values.forEach((row, i) => {
if (row.length !== cols) {
throw new Error(`列数が合いません:範囲は${cols}列、配列の${i + 1}行目は${row.length}列`);
}
});
}
function sizeCheckExamples() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
const range = sheet.getRange(2, 5, 5, 1); // E2:E6(5行×1列)
const cases = {
'1次元配列': [1200, 2000, 2400, 4500, 9600],
'行数が足りない': [[1200], [2000], [2400]],
'列数が多い': [[1200, 'x'], [2000, 'x'], [2400, 'x'], [4500, 'x'], [9600, 'x']],
'正しい形': [[1200], [2000], [2400], [4500], [9600]],
};
for (const [name, values] of Object.entries(cases)) {
try {
assertSameSize(range, values);
Logger.log(`${name} → OK`);
} catch (e) {
Logger.log(`${name} → ${e.message}`);
}
}
}
モックでの出力:
1次元配列 → 値は2次元配列(配列の配列)で渡してください
行数が足りない → 行数が合いません:範囲は5行、配列は3行
列数が多い → 列数が合いません:範囲は1列、配列の1行目は2列
正しい形 → OK
| 合わない原因 | 例 | 直し方 |
|---|---|---|
| 1次元配列を渡している | [1200, 2000, 2400] |
縦1列なら values.map(v => [v]) で [[1200],[2000],[2400]] にする。横1行なら [values] で包む |
| 行数が違う | 範囲は5行、配列は3行 | 範囲を配列から作る:getRange(開始行, 開始列, values.length, values[0].length) |
| 列数が違う | 範囲は1列、配列は2列 | 同上。または map で必要な列だけ取り出す |
| 行ごとに列数がばらばら | [[1, 2], [3]] |
足りないところを空文字で埋めて、全行を同じ長さにする |
| 行数を「終わりの行番号」で指定している | getRange(2, 5, 6, 1) に5行の配列 |
3つ目の引数は行数。2〜6行目は 5 行 |
いちばん確実なのは、範囲の大きさを配列から決める書き方です。values.length が行数、values[0].length が列数なので、次の形にしておけば大きさは必ず合います。
sheet.getRange(startRow, startColumn, values.length, values[0].length).setValues(values);
セルを1つずつ書く処理を一括書き込みに直す
数量×単価を金額の列に入れる処理を、2通りで書きます。
直す前:1セルずつ読み書きする
// 直す前:セルを1つずつ読み、1つずつ書く
function fillAmountOneByOne() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
const lastRow = lastRowInColumn(sheet, 1);
for (let row = 2; row <= lastRow; row++) {
const qty = sheet.getRange(row, 3).getValue();
const price = sheet.getRange(row, 4).getValue();
sheet.getRange(row, 5).setValue(qty * price);
}
}
直した後:まとめて読み、配列で計算し、まとめて書く
// 直した後:まとめて読み、配列の中で計算し、まとめて書く
function fillAmountBatch() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
const lastRow = lastRowInColumn(sheet, 1);
const numRows = lastRow - 1;
if (numRows < 1) return;
const source = sheet.getRange(2, 3, numRows, 2).getValues(); // 数量と単価を1回で読む
const amounts = source.map(([qty, price]) => [qty * price]); // 1列ぶんの2次元配列にする
const target = sheet.getRange(2, 5, numRows, 1);
assertSameSize(target, amounts);
target.setValues(amounts); // 1回で書く
}
モックでの出力(どちらも同じ結果になり、違うのは読み書きの回数です):
fillAmountOneByOne → E2:E6 = [[1200],[2000],[2400],[4500],[9600]] 読み書きの回数 = 16
fillAmountBatch → E2:E6 = [[1200],[2000],[2400],[4500],[9600]] 読み書きの回数 = 3
1000行 fillAmountOneByOne: 読み書きの回数 = 3001, E1001 = 700
1000行 fillAmountBatch: 読み書きの回数 = 3, E1001 = 700
モックで getValue・getValues・setValue・setValues が呼ばれた回数を数えると、5行の表で 16回 と 3回、1,000行の表では 3,001回 と 3回になりました。1セルずつの書き方は行数に比例して回数が増え、一括の書き方は行数が増えても3回のままです(どちらも最終行を調べる1回を含みます)。
Google 公式の「Best Practices」も、次のように説明しています。
- スクリプトの中で JavaScript として処理するほうが、ほかのサービスを呼び出すより速い
- 読み込みと書き込みを交互にくり返すと遅くなる。1回の命令でデータを配列に読み込み、配列の上で処理し、1回の命令で書き出す
- 公式のサンプル(100×100 のセルに色を付ける処理)では、1セルずつ書くコードが約70秒、まとめて書くコードが約1秒
処理が長くなると、実行時間の上限にも関わってきます。公式の「Quotas for Google Services」に書かれている上限は次のとおりです(上限は予告なく変わることがあると明記されています)。
| 項目 | 上限 |
|---|---|
| スクリプトの実行時間 | 6分/1回の実行 |
| カスタム関数の実行時間 | 30秒/1回の実行 |
複数の行をまとめて追加する
appendRow は1行ずつ足すメソッドなので、何行もあるときは setValues でまとめて書くほうが呼び出しが少なくて済みます。
function appendManyRows() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
const newRows = [
['A-006', 'ファイル', 8, 300],
['A-007', 'ノート', 15, 120],
['A-008', 'マウス', 5, 1500],
];
const startRow = lastRowInColumn(sheet, 1) + 1; // A列の最終行の次から
const target = sheet.getRange(startRow, 1, newRows.length, newRows[0].length);
assertSameSize(target, newRows);
target.setValues(newRows);
}
モックでの出力(書き込み後に A7:D9 を読み直した結果):
A7:D9 = [["A-006","ファイル",8,300],["A-007","ノート",15,120],["A-008","マウス",5,1500]] getLastRow = 9
A列の最終行(6行目)の次の7行目から3行が入りました。H8 のメモがあっても、表のすぐ下に続けて書けています。
V8構文でまとめて読み、集計する
Apps Script の V8 ランタイムでは、let/const、アロー関数、分割代入、テンプレートリテラルなどの書き方が使えます(公式ガイド「V8 Runtime Overview」)。2次元配列の処理は、これらを使うと短く書けます。
function summarizeWithV8() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('注文');
const [header, ...rows] = sheet.getDataRange().getValues(); // 分割代入で見出しとデータに分ける
const items = rows
.filter(row => row[0] !== '' && typeof row[2] === 'number') // 注文IDがあり数量が数値の行だけ
.map(([id, name, qty, price]) => ({ id, name, amount: qty * price }));
const total = items.reduce((sum, item) => sum + item.amount, 0);
Logger.log(`見出し: ${header.filter(h => h !== '').join(' / ')}`);
Logger.log(`件数: ${items.length}件、合計: ${total}`);
Logger.log(items[0]);
}
モックでの出力:
見出し: 注文ID / 商品 / 数量 / 単価 / 金額 / 備考
件数: 5件、合計: 19700
{"id":"A-001","name":"ノート","amount":1200}
| 構文 | コードの中の例 | 役割 |
|---|---|---|
const/let |
const sheet = … |
再代入しない値は const、ループの変数などは let |
| 分割代入 | const [header, ...rows] = … |
配列の1行目を見出し、残りをデータとして受け取る |
| アロー関数 | row => row[0] !== '' |
filter・map・reduce に渡す短い関数 |
| 引数の分割代入 | ([id, name, qty, price]) => … |
1行ぶんの配列を、列ごとの名前で受け取る |
| テンプレートリテラル | Logger.log に渡している、バッククォートで囲んだ文字列 |
文字列の中に ${…} で値を埋め込む |
V8 ランタイムは、マニフェストファイル appsscript.json の runtimeVersion を V8 にすると有効になります。
大量のデータを扱うときのチェックリスト
- [ ] ループの中に
getValue・setValue・getRange(...).getValues()が入っていないか(入っていたら、ループの外でまとめて読み書きする) - [ ] 読むのは必要な列・行だけにしているか(
getRange(2, 3, numRows, 2)のように絞る) - [ ] 書き込む配列は、全行が同じ列数になっているか
- [ ] 範囲の大きさを
values.lengthとvalues[0].lengthから決めているか - [ ] 最終行は、基準にする列を決めて数えているか
- [ ] 1回の実行が6分に収まる量か。収まらない量は、処理する行の範囲を分けて複数回に分ける
よくある質問
Q. getRange(2, 3, 6, 4) と書いたら、思ったより広い範囲になりました。
A. 3つ目と4つ目の引数は、終わりの行・列ではなく行数と列数です。getRange(2, 3, 6, 4) は C2 から6行×4列、つまり C2:F7 を指します。C2:D6 を指したいときは getRange(2, 3, 5, 2) です。
Q. 1列だけの配列を setValues で書きたいです。
A. [10, 20, 30] のような1次元配列は、values.map(v => [v]) で [[10],[20],[30]] に変えてから渡します。範囲は getRange(開始行, 列, values.length, 1) にします。
Q. getLastRow の結果が、表の行数より大きくなります。
A. 表より下のどこかの列に入力があると、その行まで数えます。この記事の lastRowInColumn(sheet, 列番号) のように、基準にする列を決めて最終行を求めてください。
Q. appendRow と setValues はどちらを使えばよいですか?
A. フォームの記録のように1件ずつ足すなら appendRow が手軽です。何行もまとめて足すときや、書き込む位置を自分で決めたいときは setValues を使います。
まとめ
- 操作はブック → シート → 範囲 → 値の順にたどる。
getSheetByNameは null の判定を入れる getRangeは行、列、行数、列数の順。3つ目・4つ目は「終わりの位置」ではなく数- 表の読み書きは
getValues/setValuesと2次元配列が基本。縦1列は[[a],[b]]、横1行は[[a,b]] setValuesの配列は範囲と同じ行数×列数にする。範囲をvalues.lengthとvalues[0].lengthから作ると必ず合う- 最終行は
getLastRow・getDataRange・特定の列の最終行の3通り。表の外に入力があるなら列を決めて数える - ループの中で1セルずつ読み書きしない。まとめて読み、配列で処理し、まとめて書く
- スクリプトの実行時間の上限は1回6分(公式の記載。変わることがある)
参考・出典
- Google for Developers「Apps Script リファレンス:Class SpreadsheetApp/Class Spreadsheet/Class Sheet/Class Range」(developers.google.com/apps-script/reference/spreadsheet、2026-10-05 閲覧)
- Google for Developers「Best Practices」「Quotas for Google Services」「V8 Runtime Overview」「Container-bound Scripts」「Extending Google Sheets」(developers.google.com/apps-script/guides、2026-10-05 閲覧)
- 型定義パッケージ @types/google-apps-script 2.0.13(npm)
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「GASスプレッドシート操作入門|getRange・setValues・最終行」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。