QUERY関数の Col1 や Col2 は、シートのA列・B列を指しているわけではありません。指定した範囲の左端から数えて1番目・2番目の列を意味します。たとえば範囲を C1:F100 と指定した場合、Col1はC列、Col2はD列、Col3はE列、Col4はF列です。それだけの話です。2026年4月時点で、この一点の誤解がQUERY数式における #VALUE! エラーや構文エラーの原因として最も多く報告されています。
QUERY関数はGoogleのVisualization API Query Languageを使用しており、select・where・group by・pivot・order by・limit・offset・label・format・options・skipping の11種類の句をサポートしています。ColN記法は、このクエリ言語がヘッダー名を使えない状況で列を特定するための表記方法です。構文を暗記するより、なぜそうなっているかを理解するほうが実務では役立ちます。
Col1・Col2と実際のシート列の対応関係
ColNの番号は、指定範囲の左端の列を1として左から右へ数えた位置を表します。主な範囲パターンでの対応は以下の通りです。
| 範囲 | Col1 | Col2 | Col3 | Col4 | Col5 |
|---|---|---|---|---|---|
A:D | A | B | C | D | — |
B:E | B | C | D | E | — |
C:F | C | D | E | F | — |
Revenue!D:H | D | E | F | G | H |
たとえば =QUERY(C1:F100, "SELECT Col1, Col3 WHERE Col2 > 1000") は、C列とE列を選択し、D列の値が1,000超の行に絞り込みます。ここで SELECT C, E WHERE D > 1000 と列文字で書いてしまうと、QUERYは構文エラーを返します。このコンテキストでは列文字を受け付けないためです。
さらに混乱を招くのは、GoogleスプレッドシートのQUERY関数ヘルプページが、場所によって列文字の例とColN記法の例を混在させており、どちらがどの文脈で有効かを明示していない点です。
列を移動するとQUERY構文が壊れる理由、そして現場での対策
範囲より前に列を挿入すると、数式内のすべてのColN参照がエラーも警告も出さずにずれます。数式は動き続けますが、返ってくるデータは意図と異なります。
例えば =QUERY(B:E, "SELECT Col1, Col2, Col4 WHERE Col3 = 'Active'") という数式があるとします。これはB列・C列・E列を返し、D列が「Active」の行に絞る意図で書かれています。ここで誰かがC列にメモ列を追加したとします。すると範囲 B:E は新しいC列を取り込み、もともとのC列はCol3へ、D列(Activeフィルター)はCol4へとそれぞれずれます。数式はそのまま動きますが、書いた時とは別の問いに答えている状態になります。BSとPLを別タブで管理しているモデルで、誰かが途中に科目列を追加したとき——そんな場面を想像するだけで背筋が伸びます。
GoogleのVisualization API Query Language仕様によれば、ColNのインデックスはクエリ実行時に渡されたデータテーブルを基準として動的に評価されるものであり、静的な束縛ではありません。
現場で機能する対策は3段階で考えるとよいです。
第1段階:範囲の終端を固定する。 B:E(終端なし)ではなく B2:E5000 と書くことで、少なくとも範囲外の列が混入するリスクを減らせます。完全な解決策ではありませんが、影響範囲を限定する効果があります。
第2段階:名前付き範囲で論理的な意味を持たせる。 GoogleスプレッドシートではデータタブからもしくはCtrl+Shift+F3(Mac:Cmd+Shift+F3)で名前付き範囲を設定できます。B2:E5000 を 売上管理テーブル という名前にしておくと、数式が =QUERY(売上管理テーブル, ...) という形になり、意図が読みやすくなります。ただし名前付き範囲自体も列挿入でずれることがある点に注意が必要です。範囲が固定列を参照していて新しい列がその内側に入ると、Googleスプレッドシートが自動で範囲を拡張してしまうことがあります。
第3段階:対応表をシートに明示する。 最も確実なのは、QUERY数式の近く(隣のセルや数式コメント、もしくはドキュメントシートの1行)に対応関係を残しておくことです。「Col1=B列(事業部)、Col2=C列(売上)、Col3=D列(ステータス)」という一行があるだけで、3ヶ月後に別の担当者がメンテナンスするときのコストが大幅に下がります。稟議や月次レポートで使い回されるシートほど、このひと手間が重要です。
QUERY構文で動的な絞り込み条件を使う
WHERE句を値ハードコードで書いていると、やがて破綻します。四半期が変わり、フィルター条件が変わり、数式の更新を忘れる——よくある話です。実務で安定して使えるパターンは、絞り込み条件をセル参照で渡す方法です。
=QUERY(B2:F5000,
"SELECT Col1, Col3, Col5
WHERE Col4 = date '"&TEXT(A2,"yyyy-mm-dd")&"'",
1)
TEXT(A2,"yyyy-mm-dd") によって、QUERYのパーサーが要求する形式に日付を変換しています。別の形式を使うと型の不一致エラーが発生します。これはQUERY固有の癖ではなく、Visualization API仕様に組み込まれた要件です。日付リテラルはISO 8601形式(yyyy-MM-dd)に従う必要があります(Query Language Reference 参照)。
テキスト条件でも同じ考え方が当てはまります。
=QUERY(B2:F5000,
"SELECT Col1, Col3, Col5
WHERE Col2 = '"&A1&"'",
1)
シングルクォートを省略すると、QUERYはセルの値を列名として解釈しようとします。クォートで囲むことで文字列リテラルとして扱われます。末尾の 1 は「1行目をヘッダーとして扱う」指定です。省略するとヘッダー行もデータとして処理されます。
四半期フィルターや担当事業部の絞り込みを毎回数式内に書き換えているシートがあれば、このパターンに置き換えるだけで即日改善できます。
複合範囲指定とColNの採番リセット
波括弧で2つの範囲を結合する場合——{Sheet1!A:D, Sheet2!E:G} のように——QUERYは結果を1つのフラットなテーブルとして扱います。ColNは結合後の左端の列からCol1として採番し直されます。Sheet2のE列はCol1ではなく、結合テーブル内の位置(たとえばCol5)になります。
これは複数シートをまたぐ集計で特に重要です。経営会議や投資家向けレポートでよく使われるパターンを示します。
=QUERY(
{Accounts!A2:C, IFERROR(
VLOOKUP(Accounts!A2:A, Deals!A:D, {2,3,4}, 0),
{"","",""})},
"SELECT Col1, Col2, Col4, Col5, Col6
WHERE Col3 = 'Enterprise'
ORDER BY Col6 DESC",
0
)
結合後の範囲は合計6列です。Accountsシートから3列(A・B・C → Col1・Col2・Col3)、VLOOKUPの結果から3列(→ Col4・Col5・Col6)という構成です。VLOOKUPを IFERROR で囲んでいるのは、対応するDealsデータが存在しないAccountsの行に空文字を入れるためです。実際の運用データでは、稼働数週間後には全体の12〜15%程度の行でこのケースが発生します。
末尾の 0(ヘッダー行数)は、シートのヘッダー行から直接引っ張るのではなく、プログラム的に範囲を組み立てているためです。
このような複合範囲は、前述の「対応表をシートに明示する」がとりわけ重要になります。ColN番号と実際の意味を対応させたコメントを一行でも残しておくと、後のメンテナンスコストが全然違います。
大規模データでのQUERY構文の扱い方
QUERYはGoogleのインフラ上でブラウザ内処理として動作します。4,800件の数値と200件のテキストが含まれる程度であればほぼ即時ですが、5万行のデータに複数のクロス集計ネストが絡むと、特に編集のたびに再計算が走る設定では処理の遅延が実感できるようになります。Google Sheetsのブック全体のセル上限は1,000万セル、QUERYの実行タイムアウトは30秒です。
大規模データで実際に効果がある対策を3点挙げます。
1. 範囲の明示的な指定 B2:F(終端なし)と書くと、QUERYは行の上限まで全スキャンします。B2:F5000 とすれば上限を絞れます。データがこの行数を超えると結果が途切れるリスクはありますが、KPIダッシュボードや予実管理などの多くのケースでは、速度のために一定のトレードオフを許容することが現実的です。
2. WHERE句の条件順序 絞り込み効果の高い条件を先に書きます。WHERE Col3 = 'Closed Won' AND Col5 > DATE '2026-01-01' は、Col3で9割の行を除外できるなら、条件を逆順に書いた場合より高速に動作します。
3. ブラウザ内計算の限界を知る 4万行のデータをQUERYで毎回集計していて、チームの誰かが編集するたびに再計算が走るような運用になっているなら、そのデータはすでにスプレッドシートではなくデータベースで扱うべきフェーズかもしれません。BigQueryやPostgreSQLへ接続して結果をシートに返す構成や、ModelMonkeyのDuckDB連携のようにSQLをそのまま書いて結果をシートに反映させる手法は、ColNのマッピング管理自体が不要になるため、大規模データの定期レポートには実用的な選択肢になります。ただし、数万行以下の通常の業務データであればQUERYで十分対応できます。
QUERY構文とFILTER関数:どちらをいつ使うか
どちらも行の絞り込みができますが、それぞれ異なる用途に最適化されています。
| 状況 | QUERY | FILTER |
|---|---|---|
| 列の選択(SELECT)が必要 | ◎ | — |
| 集計(GROUP BY、SUM)が必要 | ◎ | — |
| 複数条件での絞り込み | どちらでも | どちらでも |
| 新しいSheetsでの動的配列出力 | どちらでも | ◎(すっきり書ける) |
| ヘッダー行の処理 | 組み込み(第3引数) | 手動 |
| 複雑なソート(ORDER BY) | ◎ | — |
| 複合範囲のクロス集計 | ◎ | 扱いにくい |
単純な行抽出であればFILTERのほうがシンプルです。8列のうち3列を選択したり、カテゴリでピボットしたり、月次でグループ化したりと、データの形を変える・集計する必要が出てきた時点でQUERYが本領を発揮します。
GoogleのSheetsドキュメントにも記載されている通り、QUERYは「Google Visualization API Query Languageによるクエリをデータに対して実行する」関数です。単なるフィルター機能ではなく、フル機能のクエリエンジンとして設計されています。
よくある質問
Q. QUERY関数でCol1と書いたのに「列が見つからない」エラーが出ます。なぜですか?
A. 最も多い原因は、範囲に指定した列数よりも大きなColN番号を使っている場合です。たとえば範囲が C:E(3列)なのに Col4 を参照するとエラーになります。また、ヘッダー行の第3引数(1 または 0)の指定を省略した場合、QUERYがデータ型を自動推定して列番号がずれることがあります。まず =QUERY(範囲, "SELECT *", 1) で全列を出力し、何列あるかを確認してください。
Q. Col1・Col2という表記とA・Bという列文字表記は、どちらをいつ使えばよいですか?
A. QUERY関数の文字列(クエリ句)の中では必ず Col1 形式を使います。列文字(A・B・C)はQUERYのクエリ句では構文エラーになります。一方、QUERY関数の**第1引数(範囲指定)**には通常通り列文字を使います(例:=QUERY(A:D, "SELECT Col1, Col2"))。混乱しやすい部分ですが、「範囲はアルファベット、クエリ句はColN」と覚えておくと整理できます。
Q. 複数シートのデータを波括弧で結合したとき、ColNの番号はどう決まりますか?
A. 波括弧 {} で複数の範囲を結合すると、QUERYはそれを1つのフラットなテーブルとして扱い、左端の列からCol1・Col2・Col3…と順番に採番します。たとえば {Sheet1!A:B, Sheet2!C:D} の場合、Sheet1のA列がCol1、B列がCol2、Sheet2のC列がCol3、D列がCol4です。各シートの元の列文字は関係なく、結合後の並び順だけがColNの番号を決めます。
Q. WHERE句にセル参照を使うと「Invalid query」エラーが出ます。どう修正すればよいですか?
A. QUERY関数のクエリ句は文字列として評価されるため、セルの値を直接埋め込む際は文字列連結(&)を使います。テキスト値はシングルクォートで囲む必要があります(例:"WHERE Col2 = '"&A1&"'")。日付の場合はさらに date ' キーワードと TEXT() 関数による書式変換が必要です(例:"WHERE Col4 = date '"&TEXT(A2,"yyyy-mm-dd")&"'")。シングルクォートや date キーワードの欠落が「Invalid query」の主な原因です。
Q. QUERYとARRAYFORMULAは組み合わせられますか?
A. QUERY関数自体がすでに配列を返すため、通常はARRAYFORMULAと組み合わせる必要はありません。むしろ組み合わせると予期しない動作を引き起こすことがあります。QUERY結果を別の計算に渡したい場合は、QUERY関数をネストするか、結果を別セルに出力してから参照する方法が安定しています。