昨日まで何の問題もなく動いていたQUERY関数が、今日セルを開いた瞬間に真っ赤なエラー表示に変わっていた。そんな経験をして、今まさにこの記事にたどり着いた方も多いのではないでしょうか。しかも厄介なことに、数式は一切いじっていないのにエラーが出るのです。「自分は何も変えていないのに、なぜ?」という疑問と焦りは、スプレッドシートを業務で使う方なら誰しもが通る道です。
QUERY関数はGoogleスプレッドシートの中でも最も強力な関数のひとつですが、その分トラブルの種類も多岐にわたります。構文のちょっとしたミスから、Googleのサーバー側の仕様変更まで、原因は実にさまざまです。この記事では、QUERY関数のエラーを「なんとなく直った」で終わらせず、根本原因を理解して二度と困らないレベルまで解説していきます。
- QUERY関数で発生する主要なエラーの種類と、それぞれの原因を体系的に把握できる内容
- 混合データ型やIMPORTRANGEとの組み合わせなど、上級者もハマりやすい落とし穴の回避方法
- エラーを未然に防ぐための実践的なテクニックとIFERROR関数を使った安全設計
そもそもQUERY関数とは何をしているのか?
エラーの原因を理解するために、まずQUERY関数の仕組みをざっくり押さえておきましょう。QUERY関数は、スプレッドシート上のデータに対してGoogle Visualization API Query Languageという独自のクエリ言語で問い合わせを行う関数です。SQLに似た書き方ができるため、データベースに触れたことがある方にはなじみやすいのですが、完全にSQLと同じではない点がトラブルの元になります。
基本的な構文は
=QUERY(データ範囲, "クエリ文字列", 見出し行数)
というシンプルなものです。第1引数にデータの範囲、第2引数にSELECTやWHEREなどを使ったクエリ文、そして第3引数に見出し行の数を指定します。第3引数は省略可能ですが、後述するとおり、この「省略」がエラーの原因になることがあるのです。
ポイントは、QUERY関数がデータ範囲を受け取るとき、セル範囲として受け取る場合と配列として受け取る場合で列の指定方法が変わるということです。セル範囲なら
A
や
B
といった列文字で指定しますが、IMPORTRANGEなどを経由した配列の場合は
Col1
や
Col2
という列番号形式になります。この違いを知らないまま数式を書くと、ある日突然エラーが出る原因になります。
QUERY関数で発生する主なエラーの種類と原因
QUERY関数のエラーにはいくつかの代表的なパターンがあります。エラーメッセージを正しく読み解くことが、最短で解決にたどり着くカギです。ここでは、実際によく遭遇するエラーを網羅的に紹介します。
PARSE_ERRORが表示される場合
「関数QUERYのパラメータ2のクエリ文字列を解析できません」というメッセージとともに表示されるのがPARSE_ERRORです。これはクエリ文の書き方に文法的な問題がある場合に発生します。
最も多い原因は、SQLでは使える
IN
句がQUERY関数ではサポートされていないことです。たとえば
"SELECT A WHERE A IN (1, 2, 3)"
と書くとPARSE_ERRORになります。QUERY関数で複数値を条件にしたい場合は、
matches
と正規表現を使って
"SELECT A WHERE A matches '1|2|3'"
のように書き換える必要があります。
また、列名がSQLの予約語と一致してしまうケースも要注意です。たとえば列名が「BY」の場合、QUERY関数はこれを
ORDER BY
や
GROUP BY
のBYと解釈してしまいます。この場合はバッククォート(`)で
`BY`
のようにエスケープすれば解決します。
NO_COLUMNエラーが表示される場合
「NO_COLUMN: Col1」のようなエラーが出た場合、クエリ文で指定した列名が実際のデータ範囲に存在しないことを意味します。このエラーが「突然」発生するケースとして有名なのが、2023年6月に起きたGoogleのサーバー側の一時的な仕様変更です。
当時、同じスプレッドシート内の別シートをIMPORTRANGEで参照していた場合に、今まで配列として扱われていたものがセル範囲として扱われるように変わり、
Col1
という列指定が通らなくなるトラブルが発生しました。この件は数日で元に戻りましたが、Google側の仕様変更でQUERY関数が突然壊れるリスクがあるという教訓を残しました。
そもそも、同じスプレッドシート内の別シートを参照するのであれば、IMPORTRANGEを使う必要はありません。
=QUERY(シート名!A:E, "SELECT A, B")
のように直接シート名で参照するのが正しい使い方です。わざわざIMPORTRANGEを挟むと、不要なサーバー通信が発生するうえにエラーの原因にもなるため、同一ファイル内では直接参照を徹底しましょう。
#VALUE!エラーが表示される場合
QUERY関数で
#VALUE!
が表示される場合、データ型の不一致が原因であることがほとんどです。QUERY関数には混合データ型の罠と呼ばれる厄介な仕様があります。
Googleの公式ドキュメントにも記載されていますが、ひとつの列に文字列と数値が混在している場合、QUERY関数は多数派のデータ型をその列の型として採用し、少数派のデータは空白(null)として扱うという仕様になっています。たとえば数値が90%、文字列が10%の列であれば、文字列のセルはすべてnullとして無視されます。
これが原因で、WHERE句の条件に合致するはずのデータが抽出されなかったり、結果が空になったりします。しかもデータを追加・削除した結果、多数派と少数派が入れ替わると、昨日まで正常に動いていた数式が突然おかしくなるのです。これこそが「突然エラーになる」典型的なパターンのひとつです。
配列結果が展開されないエラーの場合
「配列結果は自動的に展開されませんでした。行(N)を挿入してください」というエラーは、QUERY関数の出力結果を表示するスペースが足りないときに発生します。QUERY関数は複数行の結果を返す関数なので、出力先のセルの下に十分な空白行がないとこのエラーが出ます。
対処法はシンプルで、出力先の下に十分な空行を確保するか、別シートに出力先を移動させるかです。目安として1000行程度の余白を確保しておけば、通常の業務データであれば問題ありません。
クエリの結果が空になるエラーの場合
「Query completed with an empty output(クエリの結果が空です)」というエラーは、WHERE句の条件に合致するデータが1件も存在しない場合に表示されます。データが本当にない場合はエラーではなく正常な動作なのですが、このメッセージが表示されるとシート上では見栄えが悪くなります。
これを防ぐには、QUERY関数全体を
IFERROR
で囲む方法が定番です。
=IFERROR(QUERY(A:E, "SELECT A WHERE B='条件'"), "該当データなし")
のように書けば、結果が空のときに任意のメッセージを表示できます。ただし、IFERRORはQUERY文自体の構文エラーも隠してしまうため、デバッグ時にはいったん外して確認する習慣をつけましょう。
混合データ型の問題を根本から解決する方法
前述のとおり、QUERY関数における混合データ型の問題は最もやっかいなトラブルのひとつです。ここでは、この問題を根本から解決するための具体的な手法を紹介します。
TO_TEXT関数ですべてを文字列に統一する
最も確実な方法は、QUERY関数に渡すデータをあらかじめ
TO_TEXT
関数で文字列に変換してしまうことです。具体的には、
=QUERY(ARRAYFORMULA(TO_TEXT(A2:E)), "SELECT Col1 WHERE Col3 = '東京'", 0)
のように書きます。
この方法を使うと列の指定が
Col1
、
Col2
という形式に変わる点に注意してください。また、すべてが文字列になるため、数値の大小比較や日付の範囲指定といった処理には向いていません。あくまで「文字列として条件一致させたい」場合に有効な手法です。
ヘルパー列を使ってデータを事前に整形する
より柔軟な方法として、元データの隣にヘルパー列(補助列)を追加し、そこでデータ型を統一してからQUERY関数で参照する方法があります。たとえば、数値と文字が混在するC列の隣に
=IF(ISNUMBER(C2), C2, VALUE(C2))
のような数式を入れた列を作り、QUERY関数ではその整形済みの列を参照するのです。
ヘルパー列を使う方法は、数式が複雑になりすぎるのを防げるうえに、どの段階でデータが変換されているかが一目瞭然になるため、チームでスプレッドシートを共有している場合にも特におすすめです。
第3引数の見出し行数を明示的に指定する
QUERY関数の第3引数を省略すると、スプレッドシートが見出し行を自動推定します。この自動推定がうまく働かないケースが意外と多く、見出し行が2行分取り込まれてデータがずれたり、逆に見出しがデータとして扱われたりします。
これを防ぐには、第3引数に
1
(見出し1行の場合)や
0
(見出しなしの場合)を必ず明示的に指定しましょう。たったこれだけの指定で、見出し行の誤判定によるエラーを完全に防げます。地味ですが、非常に効果の高い対策です。
IMPORTRANGEとQUERY関数を組み合わせるときの注意点
別のスプレッドシートファイルからデータを取り込んでQUERY関数で処理するというのは、業務でよく使われるパターンです。しかし、この組み合わせには固有のトラブルがいくつか存在します。
列指定がCol形式になることを忘れない
IMPORTRANGEで取得したデータは配列として扱われるため、QUERY関数内の列指定は
A
や
B
ではなく
Col1
、
Col2
の形式にする必要があります。
=QUERY(IMPORTRANGE("スプレッドシートID", "シート!A:E"), "SELECT Col1, Col2 WHERE Col3 > 100")
のように書きます。
この仕様を知らずに
SELECT A, B
と書いてしまうのは、初心者が最も陥りやすいミスのひとつです。列文字での指定が通るのは、同じスプレッドシート内のセル範囲を直接参照している場合だけだと覚えておいてください。
データ量が多いとエラーになる場合がある
IMPORTRANGEには読み込めるデータ量に上限があります。大量のデータを一度に取り込もうとすると、処理がタイムアウトしてエラーになることがあります。
この場合は、QUERY関数の中でさらにIMPORTRANGEを分割して呼び出し、それぞれの結果を結合する方法が有効です。具体的には、
=QUERY({IMPORTRANGE("ID", "シート!A1:E10000"); IMPORTRANGE("ID", "シート!A10001:E20000")}, "SELECT Col1")
のように中括弧で配列を縦に結合します。ただし、データ量が膨大な場合はスプレッドシートの200万セル制限にも注意が必要です。
アクセス許可を忘れずに行う
IMPORTRANGEを初めて使う際には、参照先のスプレッドシートへのアクセス許可が必要です。セルに
#REF!
エラーが表示され、「アクセスを許可」というボタンが出た場合は、必ずクリックして許可してください。一度許可すれば以降は自動で更新されますが、参照先ファイルの共有設定が変更されると再度エラーになることがあります。
エラーを未然に防ぐための実践テクニック
ここまでエラーの種類と対処法を見てきましたが、そもそもエラーが起きにくいQUERY関数の書き方を身につけることが、一番の時短になります。
IFERROR関数で安全にラップする
本番運用するQUERY関数には、必ず
IFERROR
を外側に付けておくのがベストプラクティスです。
=IFERROR(QUERY(...), "")
とすれば、どんなエラーが発生してもセルには空文字が表示されるだけで済みます。
ただし繰り返しになりますが、IFERRORは本来のエラーメッセージを隠してしまいます。開発・デバッグの段階ではIFERRORを外し、完成して運用フェーズに入ったタイミングでIFERRORを付ける、という使い分けがおすすめです。
クエリ文をセル参照で組み立てる
クエリ文を直接数式の中に書くと、長くなるにつれてミスが増えます。クエリ文を別のセルに入力しておき、QUERY関数ではそのセルを参照する方法を取ると、見通しがよくなりデバッグもしやすくなります。
たとえば、G1セルに
SELECT A, B WHERE C > 100 ORDER BY A DESC
と入力しておき、QUERY関数では
=QUERY(A1:E, G1, 1)
と書くだけです。クエリ文を変更したいときもG1セルを編集するだけで済むため、メンテナンス性が格段に向上します。
列文字は必ず大文字で指定する
意外と見落とされがちですが、QUERY関数内の列指定は大文字でなければなりません。
SELECT a, b
と小文字で書くとエラーになります。一方、SELECTやWHEREなどのキーワードは大文字でも小文字でも動きます。「キーワードは自由、列文字は大文字」と覚えておきましょう。
日付条件にはdate文字列リテラルを使う
日付を条件にする場合、QUERY関数では
date 'yyyy-MM-dd'
という独特のフォーマットを使います。たとえば
"WHERE A >= date '2026-01-01'"
のように書きます。スプレッドシートの表示フォーマットが「2026/01/01」であっても、QUERY文中では必ずハイフン区切りの
yyyy-MM-dd
形式を使ってください。
また、QUERY関数内で月番号を使う場合、月は0から始まる(1月が0、12月が11)という点にも注意が必要です。この仕様はJavaScriptのDateオブジェクトに由来するもので、知らないと1ヶ月ズレた結果が返ってきます。
情シス歴10年超の現場で見てきたQUERY関数トラブルの実態
ここからは、筆者が情報システム部門で10年以上にわたり社内のスプレッドシート運用を支えてきた経験をもとに、ネット上の記事ではなかなか語られない「現場のリアル」をお伝えします。QUERY関数のエラーで本当に困るのは、構文ミスのような単純なものではありません。もっと厄介なのは、「誰かが元データをいじったせいで、別の人のシートが壊れる」という連鎖的なトラブルです。
たとえば、営業部がマスタデータのシートに新しい列を挿入したとします。すると、経理部が参照していたQUERY関数の列指定がひとつずつズレて、まったく別のデータを集計し始めるのです。しかもこのズレは、エラーが出ずに「間違った結果を正しそうに返す」ケースがあるため、発見が遅れることがあります。月次の売上集計が実は2ヶ月間ズレていた、なんていう冗談のような本当の話も珍しくありません。
もうひとつよくあるのが、共有スプレッドシートにおける同時編集の問題です。複数人が同じスプレッドシートを編集していると、一時的にQUERY関数の参照範囲に不整合が生じてエラーが表示されることがあります。これはブラウザをリロードすれば直るケースがほとんどですが、初めて見る人はパニックになりがちです。情シスへの問い合わせで「QUERY関数が壊れました!」と来た場合、まず「リロードしてみてください」と伝えると、半分以上はそれで解決します。
列の挿入や削除で参照がズレる問題への対策
この問題はQUERY関数の構造的な弱点です。QUERY関数は
SELECT A, B, C
のように列文字で参照しますが、元データに列が挿入されると、A列だったものがB列になるのに、数式側は変わりません。通常のセル参照なら自動調整されますが、QUERY関数のクエリ文字列は「ただの文字列」なので自動調整が効かないのです。
対策として最も確実なのは、QUERY関数の参照範囲をA:Z全体ではなく、名前付き範囲で管理する方法です。「データ」メニューの「名前付き範囲」機能を使い、参照するデータ範囲に「売上マスタ」のような名前をつけておきます。こうしておけば、列の挿入があっても名前付き範囲が追従してくれるため、QUERY関数に影響が出にくくなります。
さらにもう一段踏み込んだ対策として、後述するGASを使ってヘッダー名から動的に列文字を取得し、QUERY文を自動生成する方法もあります。これなら列の並び順が変わっても、ヘッダー名さえ変更されなければ正しく動き続けます。
GASでQUERY関数のトラブルを自動検知・自動修復する
ここからは、QUERY関数まわりのトラブルを未然に防いだり、発生時に即座に対応するためのGoogle Apps Script(GAS)のコードを紹介します。どれもコピペでそのまま使えるように書いていますので、「拡張機能」→「Apps Script」を開いて貼り付けて試してみてください。
混合データ型を自動検出してアラートを出すスクリプト
先ほど解説した「混合データ型の罠」を事前に検出するためのGASです。指定した列のデータ型を調べ、文字列と数値が混在している場合にアラートを表示します。これをトリガーで定期実行すれば、混合データ型の問題が起きる前に気づくことができます。
function checkMixedDataTypes() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("データシート"); // チェック対象のシート名
var lastRow = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
var data = sheet.getRange(2, 1, lastRow - 1, lastCol).getValues();
var headers = sheet.getRange(1, 1, 1, lastCol).getValues();
var alerts = ;
for (var col = 0; col < lastCol; col++) {
var hasNumber = false;
var hasString = false;
var numberCount = 0;
var stringCount = 0;
for (var row = 0; row < data.length; row++) {
var val = data;
if (val === "" || val === null) continue;
if (typeof val === "number") {
hasNumber = true;
numberCount++;
} else if (typeof val === "string") {
hasString = true;
stringCount++;
}
}
if (hasNumber && hasString) {
var minority = numberCount < stringCount ? "数値" : "文字列";
var minCount = Math.min(numberCount, stringCount);
alerts.push(
"【警告】" + headers + "列(" + (col + 1) + "列目)に" +
"数値" + numberCount + "件と文字列" + stringCount + "件が混在しています。" +
"QUERY関数では" + minority + "側の" + minCount + "件がnull扱いになる可能性があります。"
);
}
}
if (alerts.length > 0) {
var message = "混合データ型の問題が検出されました:\n\n" + alerts.join("\n\n");
MailApp.sendEmail(Session.getActiveUser().getEmail(), "【スプレッドシート警告】混合データ型を検出", message);
Logger.log(message);
} else {
Logger.log("混合データ型の問題は検出されませんでした。");
}
}
このスクリプトのポイントは、単に「混在している」という事実だけでなく、どちらが少数派でnull扱いになるかまで判定してくれる点です。問題の発生前にメール通知を受け取れるので、「突然QUERY関数がおかしくなった」というトラブルを未然に防げます。
QUERY関数を含むセルのエラーを一括検出するスクリプト
大規模なスプレッドシートになると、QUERY関数がどのセルに入っているのか把握しきれなくなります。以下のGASは、シート内のすべてのQUERY関数を検出し、エラーが出ているものをリストアップします。
function detectQueryErrors() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var errorLog = ;
sheets.forEach(function(sheet) {
var formulas = sheet.getDataRange().getFormulas();
var values = sheet.getDataRange().getDisplayValues();
for (var i = 0; i < formulas.length; i++) {
for (var j = 0; j < formulas.length; j++) {
var formula = formulas.toUpperCase();
if (formula.indexOf("QUERY") !== -1) {
var displayValue = values;
var cellRef = sheet.getRange(i + 1, j + 1).getA1Notation();
var isError = displayValue.toString().indexOf("#") === 0 ||
displayValue.toString().indexOf("エラー") !== -1;
if (isError) {
errorLog.push({
sheet: sheet.getName(),
cell: cellRef,
formula: formulas,
error: displayValue
});
}
}
}
}
});
if (errorLog.length > 0) {
var logSheet = ss.getSheetByName("QUERYエラーログ");
if (!logSheet) {
logSheet = ss.insertSheet("QUERYエラーログ");
logSheet.appendRow);
}
var now = new Date();
errorLog.forEach(function(err) {
logSheet.appendRow);
});
Logger.log(errorLog.length + "件のQUERYエラーを検出しました。");
} else {
Logger.log("QUERYエラーは検出されませんでした。");
}
}
このスクリプトは、スプレッドシート内の全シートを横断的にスキャンし、QUERY関数を含むセルの中でエラーが表示されているものだけを「QUERYエラーログ」シートに記録します。トリガーで毎朝1回自動実行するように設定しておけば、週明け出社したらエラーが起きていた、という事態を未然に察知できます。
ヘッダー名から動的にQUERY文を生成するスクリプト
列の挿入・削除で参照がズレる問題への根本解決として、ヘッダー名をもとにQUERY文を自動生成するGASを紹介します。このスクリプトがあれば、列の順序が変わっても正しい列を参照し続けます。
function buildDynamicQuery() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("元データ");
var outputSheet = ss.getSheetByName("集計結果");
var headers = sourceSheet.getRange(1, 1, 1, sourceSheet.getLastColumn()).getValues();
// ヘッダー名から列文字を取得する関数
function getColLetter(headerName) {
var index = headers.indexOf(headerName);
if (index === -1) {
throw new Error("ヘッダー「" + headerName + "」が見つかりません。");
}
return String.fromCharCode(65 + index); // A=65
}
try {
var colName = getColLetter("氏名");
var colDept = getColLetter("部署");
var colSales = getColLetter("売上");
var sheetName = sourceSheet.getName();
var queryFormula = '=QUERY(\'' + sheetName + '\'!A:' +
String.fromCharCode(65 + headers.length - 1) +
', "SELECT ' + colName + ', ' + colDept + ', SUM(' + colSales + ')' +
' WHERE ' + colSales + ' > 0' +
' GROUP BY ' + colName + ', ' + colDept +
' ORDER BY SUM(' + colSales + ') DESC' +
' LABEL SUM(' + colSales + ') \'売上合計\'", 1)';
outputSheet.getRange("A1").setFormula(queryFormula);
Logger.log("QUERY関数を正常にセットしました: " + queryFormula);
} catch (e) {
Logger.log("エラー: " + e.message);
MailApp.sendEmail(
Session.getActiveUser().getEmail(),
"【緊急】QUERY関数の自動生成でエラー発生",
"エラー内容: " + e.message + "\n\n" +
"ヘッダー行の列名が変更された可能性があります。確認してください。"
);
}
}
このスクリプトの真価は、ヘッダー名が見つからなかった場合にエラーメールを飛ばしてくれる点にあります。誰かがヘッダーの文言を勝手に変えた場合、黙ってデータがズレるのではなく、即座にアラートが上がるのです。情シスの現場では「エラーが出ないトラブル」が最も怖いので、この仕組みは非常に重要です。
現場で本当によく起きるけど解決法がわからない5つの問題
ここでは、検索してもなかなか答えが見つからない「実務で頻発するQUERY関数の困りごと」を取り上げます。どれも筆者が実際に社内対応で何度も遭遇してきたものです。
問題1QUERY関数の結果が勝手に文字化けしたように見える
これは文字化けではなく、先述の混合データ型の問題で、数値のセルが空白に変換されたことで「行がズレた」結果です。見た目としては、データが歯抜けになったり、本来B列のデータがA列に表示されたりして、まるで文字化けしたように見えます。
対処法は明快です。参照しているデータ範囲の各列について、データ型が統一されているか確認することが第一歩です。手っ取り早く確認するには、対象列を選択して「データ」→「データクリーンアップ」→「データ型を修正」を使います。もしくは、先ほど紹介したGASの混合データ型検出スクリプトを使ってください。
問題2QUERY関数の実行がやたら遅い、または結果が表示されるまで何十秒もかかる
QUERY関数の参照範囲を
A:Z
のように列全体で指定していませんか? 列全体の指定は、空行を含むすべての行を処理対象にするため、データが数百行しかなくてもシート全体(最大1000万セル)を読みに行ってしまいます。
対処法は、参照範囲を
A1:E500
のように具体的に指定することです。しかし、データ行数が可変の場合は毎回手動で変更するわけにもいきません。そこで使えるテクニックがINDIRECT関数との組み合わせです。
=QUERY(INDIRECT("A1:E" & COUNTA(A:A)), "SELECT A, B", 1)
のように書けば、A列にデータが入っている行数だけを動的に参照範囲にできます。これだけで体感速度が劇的に改善するケースがあります。
問題3他部署が管理するスプレッドシートを参照しているQUERY関数が月曜日だけエラーになる
信じられないかもしれませんが、これは実際によく起きます。原因は、週末にGoogleの定期メンテナンスやキャッシュのクリアが行われることで、IMPORTRANGE経由の参照が一時的に途切れるためです。また、参照先のスプレッドシートのオーナーがアカウントのセキュリティ設定を変更した場合にも同様の現象が起きます。
根本的な対策としては、IMPORTRANGE経由のQUERY関数に依存しすぎないことです。重要なデータはGASで定期的にデータをコピーして自シートに保持する方法に切り替えることを強くおすすめします。以下にそのスクリプトを示します。
function syncExternalData() {
try {
var sourceId = "参照先スプレッドシートのIDをここに入力";
var sourceSS = SpreadsheetApp.openById(sourceId);
var sourceSheet = sourceSS.getSheetByName("売上データ");
var sourceData = sourceSheet.getDataRange().getValues();
var targetSS = SpreadsheetApp.getActiveSpreadsheet();
var targetSheet = targetSS.getSheetByName("同期データ");
if (!targetSheet) {
targetSheet = targetSS.insertSheet("同期データ");
}
targetSheet.clearContents();
targetSheet.getRange(1, 1, sourceData.length, sourceData.length).setValues(sourceData);
// 同期成功のタイムスタンプを記録
var metaSheet = targetSS.getSheetByName("同期ログ");
if (!metaSheet) {
metaSheet = targetSS.insertSheet("同期ログ");
metaSheet.appendRow);
}
metaSheet.appendRow);
Logger.log("同期完了: " + sourceData.length + "行");
} catch (e) {
Logger.log("同期エラー: " + e.message);
MailApp.sendEmail(
Session.getActiveUser().getEmail(),
"【警告】外部データ同期に失敗しました",
"エラー内容: " + e.message + "\n\n" +
"参照先スプレッドシートのアクセス権限を確認してください。"
);
}
}
このスクリプトをトリガーで毎朝6時に自動実行するように設定しておけば、出社する頃には最新データが自シートにコピーされています。QUERY関数はこの「同期データ」シートを参照するようにすれば、IMPORTRANGE起因のエラーとは完全に無縁になります。
問題4QUERY関数で日本語の条件指定がうまく動かない
WHERE句で日本語の文字列を条件にしたとき、全角スペースや見えない制御文字が混入していてマッチしないケースがあります。データを外部システムからコピペした場合に特に多く発生します。
目視では同じ文字列に見えるのに条件にヒットしない場合は、
TRIM
関数と
CLEAN
関数の合わせ技でデータを洗浄してみてください。具体的には、ヘルパー列に
=TRIM(CLEAN(A2))
と入れ、洗浄済みデータに対してQUERY関数を適用します。
また、全角数字と半角数字が混在するケースも厄介です。「123」(全角)と「123」(半角)はQUERY関数では別の値として扱われるため、
ASC
関数で半角に統一しておくことも有効です。
問題5QUERY関数の結果を別のQUERY関数で参照しようとしたら「循環参照」と言われた
これは直接的な循環参照ではなくても、QUERY関数の出力範囲と入力範囲が重なっている場合に発生します。たとえば、A列のデータをQUERY関数で処理してB列に出力し、そのB列をさらに別のQUERY関数で処理してC列に出力する、という構成自体は問題ありません。しかし、最初のQUERY関数の参照範囲を
A:C
のように広く取ってしまうと、自分の出力先であるB列まで参照範囲に含まれてしまい、循環参照扱いになるのです。
対策は、QUERY関数の参照範囲を必要最小限にすることです。具体的には
A:A
のように必要な列だけを指定するか、あるいは「入力用シート」と「出力用シート」を明確に分けて運用することで、参照の循環を防げます。
QUERY関数の運用で差がつくプロの管理テクニック
個人で使う分にはQUERY関数をそのまま書けばいいのですが、チームや組織で運用する場合は、もう少し「管理」の視点が必要です。ここでは、情シス目線で特に効果が高いと感じているテクニックを紹介します。
QUERY関数に必ずコメントセルをつける
QUERY関数は複雑になると、書いた本人ですら半年後に読み返せなくなります。数式の隣のセルに「この数式は何をしているのか」「どの条件で何を抽出しているのか」をメモしておくだけで、将来のトラブル対応が格段に楽になります。
さらに一歩進めて、数式を記載した「設計書シート」を同じスプレッドシート内に作っておくと便利です。設計書シートにはQUERY関数が入っているセルの場所、目的、参照先、最終更新日を一覧にしておきます。担当者が異動しても引き継ぎがスムーズになります。
重要なQUERY関数にはバージョン管理の仕組みを入れる
スプレッドシートにはGoogleの自動バージョン履歴がありますが、どの変更がどの影響を及ぼしたかを追うには不十分です。以下のGASは、QUERY関数を含むセルの数式が変更された場合に、その変更履歴を記録します。
function onEdit(e) {
if (!e) return;
var range = e.range;
var sheet = range.getSheet();
var formula = range.getFormula();
if (formula && formula.toUpperCase().indexOf("QUERY") !== -1) {
var logSheet = e.source.getSheetByName("数式変更ログ");
if (!logSheet) {
logSheet = e.source.insertSheet("数式変更ログ");
logSheet.appendRow);
}
logSheet.appendRow[
new Date(),
sheet.getName(),
range.getA1Notation(),
formula,
Session.getActiveUser().getEmail()
]);
}
}
このスクリプトはonEditトリガー(セル編集時に自動実行)を使っています。QUERY関数を含むセルが変更されるたびに「数式変更ログ」シートに記録が残るので、「誰がいつ何を変えたか」が完全に追跡可能になります。トラブルが起きたとき、犯人探しではなく原因特定のために、この仕組みは想像以上に役立ちます。
GASのトリガー設定で気をつけるべきこと
紹介してきたGASをトリガーで自動実行する際、ひとつ重要な注意点があります。GASには1日あたりの実行時間の上限があり、無料のGoogleアカウントでは合計90分、Google Workspaceアカウントでは合計6時間です。トリガーを増やしすぎると、この上限に引っかかって途中でスクリプトが止まることがあります。
対策として、複数のスクリプトを1つの関数にまとめて、1回のトリガー実行で済むようにすることをおすすめします。たとえば、混合データ型チェック→QUERYエラー検出→外部データ同期、という流れをひとつの
dailyMaintenance()
関数にまとめ、毎朝1回だけトリガー実行するようにすれば、リソースの消費を最小限に抑えられます。
ぶっちゃけこうした方がいい!
ここまでいろいろと細かいテクニックを紹介してきたけれど、正直に言って、QUERY関数のトラブルに10年以上つきあってきた身としては、「QUERY関数に頼りすぎない設計をすること」が一番大事だと思っています。
QUERY関数って、確かにめちゃくちゃ便利です。SQL風にデータを引っ張ってこれて、GROUP BYもORDER BYもPIVOTも一発で書ける。でも、それは裏を返すと、ひとつの数式にあまりにも多くの責務を持たせすぎているということでもあるんですよね。ひとつのQUERY関数が壊れただけで、それに依存しているシート全体が連鎖的に死ぬ、なんていうのは設計として健全じゃない。
個人的にはこうしたほうが、ぶっちゃけ楽だし効率的だと思います。まず、QUERY関数は「読み取り専用の表示層」としてだけ使うこと。元データの加工や変換はQUERY関数の中でやらずに、ヘルパー列かGASで事前に済ませておく。QUERY関数がやるのは、きれいに整形されたデータをSELECTして表示するだけ。こうすると、エラーが出たときに「QUERY関数が悪いのか、データが悪いのか」の切り分けが一瞬で終わります。
それから、別のスプレッドシートからデータを引っ張るのにIMPORTRANGEとQUERYの合わせ技を多用しているなら、そろそろGASへの移行を真剣に考えたほうがいいです。IMPORTRANGEは便利だけど、アクセス権限の問題、データ量の上限、キャッシュの不整合、リアルタイム性のなさと、トラブルの温床になりやすい。GASで毎朝データを同期する仕組みにしてしまえば、これらの問題は全部なくなります。しかもGASならエラーハンドリングもメール通知もログも全部入れられるので、何かあったときの対応スピードが桁違いです。
最後にもうひとつ。「動いているから触らない」は最悪の運用方針です。QUERY関数は、データの変化やGoogle側の仕様変更で、ある日突然壊れる可能性がある関数です。だからこそ、動いているうちに定期的にデータ型のチェックをして、参照範囲を見直して、ドキュメントを更新しておく。これを怠ると、壊れたときのダメージが倍になります。予防医療と同じで、健康なときにこそメンテナンスするのが、結局は一番コストが低いんです。この記事で紹介したGASのスクリプトは、まさにそのための「定期健康診断」だと思って、ぜひ導入してみてください。
QUERY関数のエラーに関するよくある疑問と解決策
昨日まで動いていたQUERY関数が急にエラーになったのですが、何も変えていません。なぜですか?
数式を一切変更していないのにエラーが出る原因として最も多いのは、参照先のデータが変わったケースです。誰かがデータを追加・削除した結果、列のデータ型の比率が変わり混合データ型の問題が顕在化することがあります。また、参照先のシート名やファイルのURLが変更された場合、参照元のスプレッドシートの共有設定が変更された場合にもエラーが発生します。まずは参照先のデータと設定を確認してみてください。まれにGoogle側のサーバー変更が原因のこともあり、その場合は数時間から数日で自然に解消されることもあります。
QUERY関数でIN句が使えないのですが、複数の値で絞り込むにはどうすればよいですか?
QUERY関数ではSQLの
IN
句はサポートされていません。代わりに
matches
キーワードと正規表現を組み合わせます。たとえば、A列の値が「東京」「大阪」「名古屋」のいずれかに一致する行を抽出したい場合は、
=QUERY(A:C, "SELECT * WHERE A matches '東京|大阪|名古屋'")
と書きます。パイプ(
|
)で区切ることでOR条件として機能します。
QUERY関数とFILTER関数はどちらを使うべきですか?
単純な条件で行を絞り込むだけであれば、FILTER関数のほうがシンプルで扱いやすいです。一方、集計(GROUP BY)、並べ替え(ORDER BY)、ピボット(PIVOT)、ラベル変更(LABEL)など、複数の処理を一発で行いたい場合はQUERY関数が圧倒的に便利です。また、FILTER関数は混合データ型の影響を受けにくいため、データ型が不揃いな環境ではFILTER関数のほうが安定して動作します。状況に応じて使い分けるのがベストです。
QUERY関数の結果をさらに別のQUERY関数で処理できますか?
はい、可能です。QUERY関数の結果を別のQUERY関数のデータ範囲として渡すことで、段階的にデータを加工できます。ただし、ネストしたQUERY関数では列指定が
Col1
形式になること、そして処理速度が低下する可能性があることに注意してください。複雑すぎるネストは可読性も下がるため、適度にヘルパー列や中間シートを活用するほうが保守しやすくなります。
今すぐパソコンやスマホの悩みを解決したい!どうしたらいい?
いま、あなたを悩ませているITの問題を解決します!
「エラーメッセージ、フリーズ、接続不良…もうイライラしない!」
あなたはこんな経験はありませんか?
✅ ExcelやWordの使い方がわからない💦
✅ 仕事の締め切り直前にパソコンがフリーズ💦
✅ 家族との大切な写真が突然見られなくなった💦
✅ オンライン会議に参加できずに焦った💦
✅ スマホの重くて重要な連絡ができなかった💦
平均的な人は、こうしたパソコンやスマホ関連の問題で年間73時間(約9日分の働く時間!)を無駄にしています。あなたの大切な時間が今この悩んでいる瞬間も失われています。
LINEでメッセージを送れば即時解決!
すでに多くの方が私の公式LINEからお悩みを解決しています。
最新のAIを使った自動応答機能を活用していますので、24時間いつでも即返信いたします。
誰でも無料で使えますので、安心して使えます。
問題は先のばしにするほど深刻化します。
小さなエラーがデータ消失や重大なシステム障害につながることも。解決できずに大切な機会を逃すリスクは、あなたが思う以上に高いのです。
あなたが今困っていて、すぐにでも解決したいのであれば下のボタンをクリックして、LINEからあなたのお困りごとを送って下さい。
ぜひ、あなたの悩みを私に解決させてください。
まとめ
QUERY関数が突然エラーになる原因は、構文ミス、混合データ型、IMPORTRANGEとの組み合わせの問題、出力先のスペース不足、そしてまれにGoogle側の仕様変更など、多岐にわたります。しかし、エラーメッセージの意味を正しく理解し、この記事で紹介した対処法を知っていれば、どんなエラーも焦らず解決できるはずです。
特に覚えておいてほしいのは、第3引数の見出し行数は必ず明示すること、混合データ型には事前にTO_TEXTやヘルパー列で対処すること、そして運用時にはIFERROR関数で安全に囲むことの3点です。この3つを徹底するだけで、QUERY関数のトラブルは大幅に減ります。
エラーは厄介に見えますが、正体がわかれば怖くありません。この記事をブックマークしておいて、次にQUERY関数がエラーを吐いたときにはぜひ見返してみてください。きっと数分で解決できるはずです。






コメント