データ分析

Google Sheets QUERY関数がサポートする機能と限界【2026年版】

Marc Sean2026年4月18日読了約 2 分

Google Sheets QUERY関数がサポートする句は、GoogleのVisualization API Query Language(GQL)に基づく8種類——SELECT、WHERE、GROUP BY、PIVOT、ORDER BY、LIMIT、OFFSET、LABEL——です。一方、多くのアナリストが壁にぶつかる機能——サブクエリ、ウィンドウ関数、クロスレンジJOIN、NULLの確実な伝播——はサポートされていません。実際の財務モデルでQUERY関数が破綻するのはこの4点であり、それらに依存したシステムを構築する前に理解しておく価値があります。

Google Sheets QUERY関数がサポートする機能

対応する句はGoogleのVisualization API Query Languageリファレンスに記載されています。2026年4月時点での対応内容は以下のとおりです。

句機能複数タブ対応
SELECT列の選択と並び替え対応
WHERE条件による行フィルタリング対応
GROUP BYSUM・AVG・COUNT・MAX・MINによる集計対応
PIVOTクロス集計対応(制限あり)
ORDER BY昇順・降順ソート対応
LIMIT行数の上限設定対応
OFFSET行のスキップ対応
LABEL出力列名の変更対応

経営企画・財務分析での実践的なユースケースとして、2万行以上の総勘定元帳から500万円超のトランザクションをすべて抽出し、コストセンター別に集計するケースを挙げます。補助列も中間レンジも不要です。

=QUERY('総勘定元帳'!A:F,
  "SELECT B, SUM(F)
   WHERE F > 5000000
   GROUP BY B
   ORDER BY SUM(F) DESC
   LABEL SUM(F) '支出合計'",
  1)

クロスタブ参照('総勘定元帳'!A:Fの形式)は問題なく機能します。QUERY関数が内部的に列をどう認識するか(Col1・Col2形式やアルファベット列参照の使い分け)については、QUERY Col1 Col2構文の解説記事で別途説明しています。

PIVOT句については特に触れておきます。ピボットテーブルを使わずに、フラットなトランザクションテーブルを損益計算書形式のマトリクスに変換できる、実用的な機能です。ただし、取締役会報告や月次経営報告での運用には重大な注意点があります。ピボット列の値は数式を書く時点で確定している必要があり、出力列は動的に生成されます。

これが意味することを具体的に説明します。四半期初めに1月・2月・3月の列で組んだPIVOT数式は、4月のデータが追加されても自動では列が増えません。4月列を追加するには数式を書き直す必要があり、その際に出力範囲がシフトします。下流でPIVOT出力の特定列をセル番地で参照している数式——たとえばサマリーシートの=集計!D5など——は、このシフトで静かにズレます。四半期末の直前に数字が消えたり変わったりするリスクが生じるため、本番の取締役会資料にPIVOT出力を直接参照させるのは避け、必ずINDEX/MATCHや名前付きレンジで値を参照する設計にしてください。

Google Sheets QUERY関数がサポートしない機能

複数タブのモデルを構築するうえで、むしろこちらのほうが重要なセクションです。GQL仕様には、明示的に対象外となっている機能が記載されています。

サブクエリ QUERYの中にQUERYをネストすることはできません。集計結果でフィルタリングしたい場合——たとえば、支出合計が1億円を超えるコストセンターだけを抽出するケースなど——は2段階のアプローチが必要です。ただし「補助レンジに出力して再度QUERY」という方法は、タブが増えるにつれてスパゲッティになります。後述するステージングタブ設計をあわせて読んでください。

ウィンドウ関数 ROW_NUMBER()、RANK()、OVER PARTITION BYによる累計計算はサポートされていません。SKU別の貢献利益分析をランキング形式で表示したい場合、補助列にデータを取り出すか、QUERY単体では対応できないと割り切る必要があります。

クロスレンジJOIN QUERYは単一の連続したレンジに対して動作します。'損益'!A:Dと'人員'!A:Cを1つのQUERY呼び出しの中でJOINすることはできません。ワークアラウンドとして{range1, range2}の配列結合で2つのレンジを統合する方法がありますが、行数が一致していなければ機能せず、上流で列が追加されると列参照がズレます。この壊れ方は静かに起きるため、気づいたときには損益と人員の数字がすでにズレた状態で上司に報告しているリスクがあります。対処法については後のセクションで説明します。

NULL処理 GQLは空白セルをnullとして扱いますが、すべての集計処理でクリーンに伝播するわけではありません。SUMはnullを正しく無視し、AVGも同様です。しかしWHERE Col3 is nullの構文は、セルが本当に空なのか長さゼロの文字列が入っているのかによって動作が安定しません。月次の集計が全行ズレる原因がこれだったというケースは珍しくありません。本番環境でnullフィルターを使う場合はIFERRORでラップし、サンプルデータで必ずテストしてください。

参考までに:5万行のトランザクションデータを30行のコストセンター集計にまとめるQUERYは、現代のGoogle Sheetsで2秒以内に処理されます。パフォーマンスはボトルネックではありません——限界はこれらの構造的な制約にあります。

壊れないQUERY数式の書き方:ステージングタブ設計

8タブ連携モデルで最も多い障害パターンは、位置参照(Col1、Col2)を使ったQUERY数式です。誰かが上流に列を1本挿入すると、位置参照ベースのQUERYはすべて静かにズレていきます。

しかし位置参照の問題より根本的なのがレンジの分散です。タブをまたいで6つのQUERYが走っている状態では、スキーマ変更の影響範囲が追いきれなくなります。

実務で有効なのは、単一のステージングタブにソースデータを集約してからクエリを一本化するアプローチです。

ステージングタブの設計方針

[データソースタブ群]          [ステージングタブ]       [分析・レポートタブ]
'4月売上'!A:F    ──┐
'5月売上'!A:F    ──┼──→  'staging'!A:G  ──→  QUERY × 1本
'6月売上'!A:F    ──┘

ステージングタブで各月のデータを縦方向に結合します。

=ARRAYFORMULA({
  '4月売上'!A2:F1000;
  '5月売上'!A2:F1000;
  '6月売上'!A2:F1000
})

この結合にARRAYFORMULAを使う利点は、行数を揃える必要がないことです。各月タブの行数が違っても問題ありません。空行が生じますが、後続のQUERYでWHERE A <> ''を加えればフィルタリングできます。

ステージングタブが用意できれば、分析タブの数式は1本に集約されます。

=QUERY(INDIRECT("'staging'!A:G"),
  "SELECT A, C, D
   WHERE C >= " & 前提条件!$B$3 & "
   AND A <> ''
   ORDER BY A",
  1)

月次決算の締め日や四半期末といった動的な日付カットオフは、セル参照の値をクエリ文字列に連結することで実現できます。上記の前提条件!$B$3パターンが正しいやり方です。クエリ文字列に日付をハードコードしないでください。

2万行のステージングレンジに対する1つのQUERYは、6つのタブに対する6つのQUERYよりも、処理速度でもデバッグのしやすさでも優れています。年度末に月別タブが12枚に増えても、ステージングのARRAYFORMULAに1行追加するだけで対応できます。

クロスレンジJOINの壊れにくい代替設計

{range1, range2}の水平結合が壊れやすい理由は、行順の一致を人間が保証しなければならないからです。損益と人員データを請求書IDで突き合わせるケースなら、QUERY内でのJOINは諦めて次の設計に切り替えてください。

1対1のルックアップはINDEX/MATCHで処理します。ステージングタブに照合キーを作り、そこにINDEX/MATCHで値を引っ張ってからQUERYにかけます。

// ステージング側(G列にINDEX/MATCHで人員データを追加)
=ARRAYFORMULA(
  IFERROR(
    INDEX('人員'!C:C, MATCH('損益'!A2:A, '人員'!A:A, 0)),
    ""
  )
)

ステージングタブがJOINの役割を担い、QUERYは集計に専念します。メンテナンス箇所が1か所に集約されるため、上司から「人員と損益の数字がズレてる」と言われたときの原因特定が数分で終わります。

LABEL句:取締役会資料の列名を整える

LABEL句は見落とされがちですが、今日から使える実用機能です。ソースデータを変えずに出力列名を変更できるため、元の列名がシステム上のコード略称であっても、取締役会報告資料の表ヘッダーをきれいに保てます。

=QUERY('売上'!A:E,
  "SELECT B, SUM(E)
   WHERE A = 'Q1'
   GROUP BY B
   LABEL B '事業部', SUM(E) 'Q1売上(円)'",
  1)

システムの列名(DIV_CDやAMT_NETなど)がそのままレポートに出ている場合、LABELで一括して表示名を上書きできます。

QUERYが適切なツールでなくなるタイミング

「QUERYをやめるべきタイミングはいつか」——この問いに対する率直な答えは、JOIN制約です。2つのデータセットを照合する分析が必要な場合、たとえば'買掛金'の3,400件の請求書を請求書IDで'資金管理'の入金記録と突き合わせるケースでは、QUERYは機能しません。前述のステージングタブ+INDEX/MATCH設計でカバーできる範囲は広いですが、複数テーブルをまたぐ集計が複雑になるにつれ、補助列と中間タブが増え続けます。

サブクエリの代替として補助レンジを使う2段階アプローチも同様で、「煩雑だが機能する」段階を超えると、数式の依存関係がスパゲッティになります。

ModelMonkeyのDuckDB連携は、タブをまたいだJOINを含む本格的なSQLをシートのレンジに対して実行できるため、こうしたケースへの出口になります。実際の構文は以下のとおりです。

SELECT ap.invoice_id, ap.amount, t.payment_date
FROM sheet_range('買掛金!A:D') ap
JOIN sheet_range('資金管理!A:C') t ON ap.invoice_id = t.invoice_id
WHERE ap.amount > 1000000

QUERYの限界が工数コストになり始めたときの選択肢です。セットアップ方法はGoogle Sheets DuckDB連携の解説記事で説明しています。

よくある質問

Q. QUERY関数とSUMIFSはどう使い分ければよいですか?

単一条件・単一集計列であればSUMIFSのほうが数式がシンプルです。複数列の選択、ソート、GROUP BYによる多軸集計が必要な場合はQUERYが優ります。条件分岐が3つ以上になったときを目安に切り替えると管理しやすくなります。

Q. QUERY関数は別のスプレッドシートファイルのデータを参照できますか?

直接の参照は原則できません。IMPORTRANGEで別ファイルのデータを現在のスプレッドシートに取り込んでから、そのレンジに対してQUERYを実行する2段階の構成が必要です。IMPORTRANGE取込先のレンジをステージングタブとして扱えば、本記事の設計パターンがそのまま適用できます。

Q. WHERE Col3 is nullが期待どおり動かない場合の対処法は?

セルが本当に空か、長さゼロの文字列("")が入っているかで動作が変わります。長さゼロの文字列が混在している場合はWHERE Col3 is null OR Col3 = ''と併記するか、ソースデータ側で=IF(A1="", , A1)のように値がない場合に完全な空白を返す数式に統一してください。本番環境では必ずサンプルデータで動作確認を行ってください。

Q. QUERY関数のパフォーマンスが遅い場合はどうすればよいですか?

5万行程度であれば通常2秒以内に処理されます。遅延が発生する場合は、複数のQUERYが同一ソースを参照していないか確認してください。ステージングタブに集約して参照元を一本化するだけで大幅に改善するケースが多いです。

Q. PIVOTで月が追加されるたびに下流の数式が壊れます。解決策はありますか?

PIVOT出力を直接セル番地で参照するのをやめ、INDEX/MATCHで列名(ヘッダー)をキーに値を引く設計に変えてください。=INDEX(集計!$1:$1000, MATCH("4月", 集計!$1:$1, 0))のように列ヘッダーを検索キーにすれば、列が増減してもズレません。取締役会直前に数字が消えるリスクを排除できます。