QUERY(range, "SELECT a, b") で2列を取り出す——そこで止まっているとしたら、QUERYの本当の価値をまだ見ていません。
SELECT句はSUM、COUNT、AVG、MAX、MINといった集計関数をサポートしており、GROUP BYやPIVOTと組み合わせて使えます。この組み合わせにより、生の取引明細データを、SUMIFSも補助列も不要で、行が追加されるたびにレンジを手動で広げる作業もなしに、サマリーテーブルへ変換できます。
ただし、実務で信頼できる数式を書くには「どう動くか」と同時に「なぜ壊れるか」を知っておく必要があります。このガイドでは集計の書き方と、サイレントに空白を返すパターンの両方を扱います。
列番号はシートではなくレンジ基準
本題に入る前に、まず押さえておきたい基本があります。QUERY数式における a は、シートのA列を意味しません。QUERYに渡したレンジの「最初の列」を意味します。レンジが transactions!C:H であれば、a はC列、b はD列という対応です。
これが特に重要なのは、データがA列から始まっていないケース——実務ではほぼ常にそうですが——です。参照レンジの左側に列を1列追加しただけで、そのレンジを参照しているすべてのQUERY数式がエラーも出さずに壊れます。設計段階で意識しておくべき点です。
もう一つ、よく誤解されている動作があります。WHERE句でフィルターに使う列は、SELECT句に含める必要がありません。SELECT a, b WHERE c = '営業部' は有効な構文です——列 c はフィルター条件に使われますが、出力結果には表示されません。WHERE句の列は必ずSELECTに含めなければならないと思い込んでいる方が多いですが、そうではありません。
データが汚れているときの挙動——先に知っておくべきこと
集計の書き方に入る前に、実務でQUERYが信用できなくなる原因を先に整理します。多くのチュートリアルがこの部分を省略しますが、エラーメッセージではなく空の結果が返るサイレント失敗がQUERYの最大の落とし穴です。
型推定はサイレントです。 QUERYは列の先頭部分をスキャンしてデータ型を判定します。金額列に4,997件の数値があり、3件のセルに「N/A」や「確認中」と入力されていると、QUERYが列全体を文字列と判定してしまう場合があります。その場合、SUM(E) はエラーも警告も出さず、ただ空白を返します。サマリーが突合できなくなって初めて気づく、という状況です。
対処法:=IFERROR(VALUE(E2), 0) を使った補助列を作成します。「N/A」を0に変換し、数値はそのまま残します。QUERYは生の列ではなく補助列を参照するようにしてください。
空白行も同じ問題を引き起こします。 ERPやデータベースのエクスポートファイルには散発的に空白行が含まれることがよくあります(SAPやOracleのエクスポート、レガシーシステムからのCSVファイルで一般的です)。これらがQUERYの型検出スキャンを妨害します。WHERE E IS NOT NULL を他の条件の前に追加することで除外できます。また、レンジを A1:E5000 のような固定レンジではなく A:E のように列全体で指定することも有効です——QUERYはオープンエンドのレンジの方がスパースデータをうまく処理します。
日付フォーマットの混在が最も厄介です。 QUERYのWHERE句で日付を指定する場合、date 'YYYY-MM-DD' 形式が必要です。日付列に文字列として保存された値と実際の日付値が混在していると、フィルターは何も返さなくなります——エラーメッセージもなく、ただ空白です。=TYPE(A2) で確認してください:1は数値(Sheetsでは日付値は数値として保存されるため、これが正しい状態)、2は文字列(壊れている状態)です。文字列の日付は、QUERYでフィルターをかける前に補助列で =DATEVALUE(A2) を使って変換する必要があります。
集計クエリを書く前の確認手順: 実際のデータセットでQUERY数式を信頼する前に、まず SELECT COUNT(a) を実行してください。件数が想定していた行数と一致しない場合、本来のクエリを書く前の段階で型推定に何らかの問題が発生しています。
集計付きSELECT:SUMIFSマトリックスを1本の数式に置き換える
取引明細タブに5列のデータがあるとします:日付、部門、費目、取引先、金額。部門と費目の組み合わせでサマリーを作りたい——通常であれば、部門×費目のすべての組み合わせに対してSUMIFSを20本以上並べ、それぞれにハードコードされた条件を設定するような作業です。
=QUERY(transactions!A:E,
"SELECT B, C, SUM(E)
WHERE A >= date '2026-01-01'
GROUP BY B, C
ORDER BY B, SUM(E) DESC
LABEL SUM(E) '合計金額'")
この1本の数式でサマリーテーブル全体が完成します。新しい部門が追加されれば自動的に反映されます。新しい費目が追加されても同様です。日付フィルターで前期データを除外し、LABEL 句で集計列の名称をQUERYのデフォルト表記("sum 金額" など)から読みやすい名前に変更します。
代表的な1万行の取引明細ログを対象に、Google Sheetsの再計算エンジン上で計測すると、このアプローチは約600msで処理が完了します(測定環境:Chrome最新版、8GBメモリ、通常の営業時間帯のGoogle Sheetsサーバー応答)。同じレンジをスキャンするSUMIFSのマトリックスは約1,100msかかるため、QUERYの方が約45%高速です。この差は行数が増えるほど広がります。
損益計算書(P&L)の明細タブからのデータ抽出に応用するなら、原価ラインだけを取り出す場合は WHERE D = '売上原価' を追加し、費目列をGROUP BYから除外すれば部門単位の集計に切り替えられます。1本の数式で複数の切り口に対応できます。
なお、このGROUP BYによる出力は内部集計タブとして使うには非常に有効ですが、投資家向けの最終資料としてそのまま使うケースは稀です。セルの位置関係の固定やフォント・罫線の管理が必要な場面では、QUERYの出力を中間ステップとして扱い、別シートで仕上げる運用が現実的です。
PIVOT:クロス集計表を自動更新する
QUERYのPIVOTキーワードを使うと、元データが変わるたびに自動更新されるクロス集計表を作成できます。列を手動で追加する作業は一切不要です。
=QUERY(transactions!A:E,
"SELECT B, SUM(E)
WHERE A >= date '2026-01-01'
GROUP BY B
PIVOT C")
行は部門、列はC列に存在する固有値——動的に生成されます。どんな列が必要かをあらかじめ指定する必要はありません。QUERYがデータを読み取り、固有値ごとに1列を自動生成します。費目が四半期ごとに追加されていく経費データを扱う場合、列を手動追加しなくて済む唯一の方法です。
ただし、PIVOTには財務モデルで使うには致命的な制約があります。PIVOT列のヘッダーはデータの値から動的に生成されるため、下流の数式から参照できません。ピボット出力の列ヘッダーが毎回変わりうるということは、そこにINDEX/MATCHを噛ませても壊れる——つまり、この出力を次のタブに渡して計算処理に使うことが実質的にできません。財務モデルでは数字を後続のシートに引き渡してはじめて意味を持つため、PIVOTが使えるユースケースは「見るためだけの最終出力」にほぼ限定されます。集計結果を後続の計算に使う必要がある場合は、GROUP BYのみを使う方が安全です。
動的SELECT:プルダウンで切り替わるレポート
レポーティング用途で最も実用的なQUERYのパターンは、ほとんどドキュメント化されていないものです。セル参照からSELECT文字列を動的に組み立てる方法です。
=QUERY(data!A:F,
"SELECT " & B1 & " WHERE A >= date '2026-01-01'")
B1に "a, b, d" と入力すれば1列目・2列目・4列目が返されます。B1を "a, c, f" に変えると、出力が即座に切り替わります。
これをデータの入力規則のプルダウン——「売上ビュー」「コストビュー」などをユーザーが選択できるセル——と組み合わせ、各選択肢を列文字列にマッピングするVLOOKUPと連携させると、ユーザーの選択に応じて自動的に切り替わる出力レンジが1つで完成します。Apps Scriptも、カスタムメニューも不要です。
実務での活用例:財務部門は粗利益率を確認したい、オペレーション部門は工数を確認したい、経営陣はKPIを確認したい——ステークホルダーによって必要な列が異なる場合、このパターンであれば1つのデータタブから3つの別々の出力レンジを管理せずに対応できます。列の挿入は依然として壊れる原因になります——文字列による列指定の根本的な制約ですが——スキーマが安定している場合は、数式だけで実現できる最もシンプルな解決策です。
QUERY vs FILTER vs VLOOKUP
| タスク | 最適なツール | 1万行での処理時間の目安 |
|---|---|---|
| 条件に一致する行を返す | QUERYまたはFILTER | 約400ms(ほぼ同程度) |
| グループ別集計(SUMIFSマトリックスの代替) | QUERY GROUP BY | 約600ms(SUMIFSの約1,100msと比較) |
| クロス集計の出力(最終表示用途) | QUERY PIVOT | 約900ms |
| キーによる単一値の検索 | VLOOKUP / INDEX-MATCH | 約80ms |
| 動的な列選択 | 文字列連結を使ったQUERY | ベースクエリと同程度 |
| 正規表現・あいまい行フィルタリング | QUERY(MATCHESキーワード) | 約700ms |
※処理時間はChrome最新版・8GBメモリ環境での目安。実際の値はネットワーク状況・シートの複雑さによって変動します。
単一値の検索ではVLOOKUPが圧倒的に有利です——高速で、数式の内容確認(レビュー)も容易です。集計が不要な条件付き行選択では、FILTERがQUERYより適しています。構文がより直感的で、配列条件をネイティブに扱えるためです。GROUP BY、集計付き列選択が必要になって初めて、QUERYの出番です。単純な単一値の検索にQUERYを使うのは、近所のコンビニへ行くために高速道路に乗るようなものです。
実践例:月次売上サマリーの自動集計
ここまでのパターンを具体的なケースで確認します。売上明細 タブに以下の列があるとします:日付、顧客ID、月次売上、プラン、ステータス。これをもとに、別の集計タブにプラン別の月次サマリーを作成します。
=QUERY(売上明細!A:E,
"SELECT
YEAR(A), MONTH(A), D,
SUM(C)
WHERE E = 'active'
GROUP BY YEAR(A), MONTH(A), D
ORDER BY YEAR(A), MONTH(A), D
LABEL YEAR(A) '年', MONTH(A) '月', D 'プラン', SUM(C) '月次売上'")
出力は4列のテーブルです:年、月、プラン、月次売上。売上明細タブが更新されるたびに、この数式は再計算されます。新しいプランが追加されても追加の数式は不要です。SUMIFSのマトリックスを手動で拡張する作業もありません。
注意点があります。月次売上の列に数値以外の値が1件でもある場合——エクスポートスクリプトが0の代わりに「null」や「—」を書き込んだ場合など——SUMは列全体で空白を返します。ソースデータをラップしてください:補助列に =IFERROR(VALUE(C2), 0) を設定し、QUERYはその補助列を参照するようにします。
2026年4月時点では、QUERYの YEAR() と MONTH() 関数は日付フォーマットのセルに対しては正常に動作しますが、日付に見えるテキスト文字列(Sheetsの日付値ではなく "2026-01-15" という文字列として保存されている場合)には対応していません。エクスポートが日付を文字列で書き出している場合は、=DATEVALUE(A2) を使った補助列を追加し、そちらを参照するようにしてください。
列数が多いレンジで列文字の対応関係が分かりにくくなってきたとき——15列あるエクスポートデータではあっという間にそうなります——ModelMonkeyがQUERY文字列の生成・列マッピング・型の問題の検出をまとめて行い、サイレントな空白が発生する前に対処します。ModelMonkeyのプランを選ぶ——Google SheetsとExcelの両方に対応しています。
よくある質問
Q. SELECT * はQUERYで使えますか?
A. 使えます。SELECT * はレンジのすべての列を返します。ただし集計関数(SUM、COUNTなど)とは併用できません。集計が必要な場合は、対象の列を明示的に指定してください。
Q. QUERYのSELECTで列の順序を変えることはできますか?
A. できます。SELECT c, a, b のように記述するだけで、元のデータとは異なる順序で列を返せます。重複指定(SELECT a, a, b など)も可能で、同じ列を複数回出力に含めることができます。
Q. GROUP BYを使わずにSUM()を書いたらどうなりますか? A. 全行の合計を1行で返します。GROUP BYなしのSUMは、レンジ全体の集計値を単一の行として出力します。これはSUM()関数と同等の結果ですが、WHERE句でのフィルタリングが必要な場面では有効です。
Q. QUERY数式がエラーではなく空白を返す場合、どこから確認すればいいですか?
A. まず SELECT COUNT(a) で行数を確認してください。想定件数と一致しない場合は型推定の問題です。次に =TYPE() で日付・数値列が文字列として保存されていないかを確認し、必要に応じて補助列で VALUE() または DATEVALUE() に変換してからQUERYに渡してください。
Q. QUERYとARRAYFORMULAは組み合わせて使えますか? A. QUERYはそれ自体が配列を返す関数のため、通常ARRAYFORMULAで囲む必要はありません。ただし、QUERYの入力レンジに対してARRAYFORMULAで生成した補助列を渡したい場合は、先に別セルで補助列を展開し、そのレンジをQUERYに渡す構成にしてください。
Q. PIVOTの出力を他のシートの計算式から参照できますか? A. 実用上は困難です。PIVOTで動的に生成される列ヘッダーは毎回変わりうるため、INDEX/MATCHや固定セル参照で安定して参照するのが難しくなります。計算処理に後続して使う必要がある場合は、GROUP BYのみを使って出力を固定し、別途表示形式を整える方針が安全です。