生成AIに「9月の売上を出すSQLを書いて」と頼むと、それらしいSQLがすぐに返ってくる。実行するとエラーもなく数字が出る。でも、この数字をそのまま報告してよいのか分からない。
最初に確認したいのは、実行する前にSQLの「条件」を読み、実行した後に「件数と合計」をすでに分かっている数字と比べること です。SQLをゼロから書けなくても、確かめる場所が決まっていれば検算はできます。
この記事でわかること
- AIに任せる作業と、人が確かめる作業の分け方
- AIが書いたSQLをそのまま実行しない5つのチェック(実行前に読む3つ・実行後に数字で確かめる2つ)
- 確認の手順を決めると業務の何が良くなるか(データ担当への依頼待ちが減り、誤った数字で報告しなくなる)
結論:AIに任せるのは「SQLを書く」まで。数字の定義と検算は人がやる
AIが書いたSQLは下書きです。実行してよいか、出た数字が正しいかを決めるのは、頼んだ人です。
生成AI(文章で頼むと、文章やSQLを作って返してくれるAI)は、SQLの下書きを書くのが得意です。一方で、会社の中で「売上」が何を指すか、どのデータを除くべきかは、渡された情報からしか分かりません。足りない部分を推測で埋めたまま、それらしいSQLを返すことがあります。
| 作業 | 誰がやるか | 理由 |
|---|---|---|
| SQLの下書きを書く | AI | 書き方の候補をすぐに出せる |
| SQLの各行が何をしているかを説明する | AI(説明は人が読んで確かめる) | 読めない箇所を減らせる |
| エラーメッセージの意味を調べる | AI | 直す場所の見当がつく |
| 「売上」「9月」など、数字の定義を決める | 人 | 社内の定義はAIには分からない |
| 実行してよいかを判断する | 人 | 更新・削除のSQLはデータそのものを書き換える |
| 結果を検算し、報告する数字を決める | 人 | 数字に責任を持つのは頼んだ人 |
進め方は「頼む前に情報を渡す → 実行前に3つ読む → 実行後に2つ確かめる」の3段です。
頼む前に:テーブル定義と「数字の定義」を渡し、入力してよいかを先に確かめる
AIに渡す情報が少ないほど、AIは列の意味や条件を推測で埋めます。
SQLを頼むときは、次の6つを文章で渡します。
- 目的:誰が、何の判断に使う数字か
- DB製品名:PostgreSQL・MySQLなど(日付の書き方などの文法が製品ごとに違うため)
- テーブル名・列名・型:特に日時の列が「日付だけ」か「日付と時刻」か
- 1行の単位:注文1件で1行か、注文の中の商品1つで1行か
- 数字の定義:「売上」は支払い済みだけか、キャンセルを除くか、税込か
- 出してほしい形:どの列を、どの単位の行で出すか
あわせて、次の2つを頼みます。
- 「SELECT文だけで書いてください」:データを読むだけのSQLに限り、更新・削除を含めないようにする
- 「置いた前提を箇条書きで出してください」:期間の境界や除外した条件が書き出されるので、実行前に読む材料になる
入力する前に、テーブル定義やデータをAIに入れてよいかを、社内のルールと使うサービスの規約で確かめます。 会社によっては、使ってよいAIサービスや入力してよい情報の範囲が決まっています。テーブル名や列名も社内の情報です。SQLを書いてもらうだけなら、顧客名や金額などの実データは入れず、定義だけで頼めます。規約や社内ルールは変わることがあるため、使い始める前と、変更の案内があったときに確かめてください。
そのまま実行しない5つのチェック:実行前に3つ読み、実行後に2つ数字で確かめる
AIのSQLの確認は、全部を読み解くことではなく、数字がずれやすい5か所を順に見ることです。
| # | いつ | 確認すること | ずれると起きること |
|---|---|---|---|
| 1 | 実行前 | テーブルと列が、渡した定義どおりか | 似た名前の別の列で集計し、定義と違う数字が出る |
| 2 | 実行前 | 期間の境界・絞り込み・WHEREとONの位置 | 月末のデータが漏れる、除くべきデータが混ざる |
| 3 | 実行前 | JOINとGROUP BYのあとの「1行の単位」 | 行が増え、合計が膨らむ |
| 4 | 実行後 | 各段階の件数 | どこで行が増えた・減ったかが分からない |
| 5 | 実行後 | すでに分かっている数字との突き合わせ | 誤った数字のまま報告する |
その前提として、SELECT以外の文(UPDATE・DELETE・INSERTなど)が含まれていたら、実行しません。
1. テーブルと列:渡した定義にある列を、意図どおりの意味で使っているか
AIは、渡していない列名をもっともらしく補うことがあります。存在しない列ならエラーで止まるので気づけます。困るのは、実在する似た名前の列です。たとえば(架空の例ですが)税抜の「amount」と税込の「amount_with_tax」があると、どちらで集計しても、エラーなく数字が出ます。SQLに出てくる列を1つずつ、定義と見比べてください。
自分がAIに書いてもらったSQLでも間違いはあり、基本的には列名・テーブル名などの命名の間違いです。だいたい、実行したときか、自分でSQLを読んだときに気づきます。
2. 条件:期間の境界、絞り込み、WHEREとONの位置
条件は、次の3か所を読みます。
- 期間:月初と月末の日が入っているか。日時の列に
BETWEENで日付だけを指定すると、月末日の0時より後が漏れます(具体例で確かめます) - 絞り込み:キャンセル・テストデータなど、除くべきものを除いているか。逆に、除きすぎていないか
- LEFT JOINのとき:右側のテーブルの条件がWHEREにあると、残したかった行まで消えます
WHEREとONの違いは、次の記事で実行例つきで整理しています。
3. 単位:JOINとGROUP BYのあとで、1行が何を表すか
注文のテーブル(注文1件で1行)に明細のテーブル(注文の中の商品1つで1行)をJOINすると、1行の単位は明細になり、注文の金額が商品の数だけ繰り返されます。FROMとJOINのあとの1行、GROUP BYのあとの1行が何を表すかを、一言で言えるか確かめます。言えないときはAIに「このSQLの結果の1行は何を表しますか」と聞き、その答えも自分で確かめます。
粒度(1行が何を表すか)の確かめ方は、次の記事で詳しく書いています。
4. 件数:JOIN前後・集計前後で、件数がどう変わったか
実行したら、元のテーブルの件数、JOINしたあとの件数、集計したあとの件数を並べます。COUNT(*) は行の数、COUNT(DISTINCT order_id) は注文の数です。両方を出すと、JOINで行が増えたかどうかが分かります。
COUNTの使い分けと、ずれた場所を分解して探す方法は、次の記事で整理しています。
5. 突き合わせ:件数と合計を、すでに分かっている数字と比べる
比べる先は、次のどれかです。
- 既存の月次レポートや、業務システムの管理画面に出ている数字
- 前月に同じ条件で出した数字
- JOINをせず、元のテーブルだけで件数と合計を出したSQLの結果
一致しないときは、日別・ID別に分けて、差の出ている行を探します。一致しない理由を説明できるまで、その数字は報告に使いません。
具体例:架空の注文データで、AIが書いたSQLを検算する
エラーなく動いても、期間の終わりの書き方1つで、9月の売上は3,000円ではなく1,000円になります(架空の例)。
以下は説明のための架空の例です。DBはPostgreSQLまたはMySQLを想定しています。ordered_at は日付と時刻を持つ列(日時型)です。
入力データ(orders)
| order_id | ordered_at | status | amount |
|---|---|---|---|
| 101 | 2026-09-01 10:00 | paid | 1,000 |
| 102 | 2026-09-30 15:00 | paid | 2,000 |
| 103 | 2026-09-15 09:00 | canceled | 500 |
| 104 | 2026-10-01 00:00 | paid | 3,000 |
「9月の支払い済み注文の件数と売上合計を出すSQL」を頼み、仮にAIが次のSQLを返したとします。
SELECT COUNT(*) AS order_count, SUM(amount) AS sales
FROM orders
WHERE status = 'paid'
AND ordered_at BETWEEN '2026-09-01' AND '2026-09-30';
実行結果
| order_count | sales |
|---|---|
| 1 | 1,000 |
なぜこうなるか:日時の列と ‘2026-09-30′ を比べると、’2026-09-30 00:00:00’ として扱われます。BETWEEN は「以上・以下」なので、範囲は9月30日の0時ちょうどまでです。9月30日15時の注文102が漏れます。ordered_at が日付だけの列(DATE型)なら、この書き方でも9月30日の注文は入ります。
どこで気づけるか:実行前ならチェック2で、期間の終わりが日付だけで書かれていることに気づけます。実行後ならチェック5で、管理画面などの「9月の支払い済み2件」と合わないことで気づけます。漏れた行は、月末日だけを取り出すと見つかります。
SELECT order_id, ordered_at, amount
FROM orders
WHERE status = 'paid'
AND ordered_at >= '2026-09-30'
AND ordered_at < '2026-10-01';
この結果に注文102が出てくれば、元のSQLで漏れていた行だと分かります。
どう直すか:期間を「9月1日以上、10月1日より前」と書きます。
SELECT COUNT(*) AS order_count, SUM(amount) AS sales
FROM orders
WHERE status = 'paid'
AND ordered_at >= '2026-09-01'
AND ordered_at < '2026-10-01';
| order_count | sales |
|---|---|
| 2 | 3,000 |
「翌月1日より前」と書くと、時刻を持つ列でも日付だけの列でも同じ結果になり、10月1日0時の注文104も入りません。なお、日付を文字列で書く方法は、DB製品や設定によって扱いが変わります。頼むときにDB製品名を伝え、そのDBの書き方で書いてもらいます。
現場目線の注意点:「エラーなく動いた」は「数字が合っている」の証拠にならない
条件や単位のずれはエラーにならず、それらしい数字として出てきます。
エラーなく動いたことを、合っている根拠にしない。 具体例のSQLもエラーは出ず、1件・1,000円を返します。この数字が会議資料に載ると、あとから差し替えと説明が必要になり、同じ資料のほかの数字まで確かめ直すことになります。
AIが書いたSQLを、読めないまま保存して使い回さない。 翌月に別の人が使うとき、どの条件が何のためにあるかが分からず、作った人に聞くしかなくなります。SQLの先頭に -- で始まるコメント行を置き、目的・数字の定義・何と突き合わせて確かめたかを書いておきます。-- (ハイフン2つのあとに半角スペース)から行の終わりまではコメントとして扱われ、実行されません。個人的には、インデント(行頭の字下げ)をとことん綺麗にそろえるのが好きです。そろっていると、どの条件がどこにかかっているかを読み取りやすくなります。
業務への着地:依頼待ちが減り、誤った数字で報告しなくなる
確認の手順が決まっていれば、AIは依頼待ちを減らす道具になり、検算は誤った数字の報告を止める仕組みになります。
- 依頼待ちが減る:数字を見たいたびにデータ担当に頼んで待っていた集計を、AIの下書きと5つのチェックで、自分で出せる範囲が広がります
- 誤った数字で報告しない:件数と合計の突き合わせを報告前の決まりにすると、ずれが資料に載る前に止まります
- 確認の仕方が人によって変わらない:5つのチェックをチームで共有すると、データ担当に見てもらうときも「何と突き合わせたか」から話せます
自分で出せる範囲を広げるのは、閲覧してよいデータ・使ってよいAIサービスなど、社内で許されている範囲の中で、が前提です。
まとめ
生成AIに書いてもらったSQLは、次の5つを確かめてから使います。
- テーブルと列が、渡した定義どおりの意味で使われているか
- 期間の境界・絞り込み・WHEREとONの位置が、意図どおりか
- JOINとGROUP BYのあとで、1行が何を表すかを言えるか
- 元のテーブル・JOIN後・集計後の件数がどう変わったか
- 件数と合計が、すでに分かっている数字と一致するか
頼む前には、テーブル定義と数字の定義を渡し、入力してよいかを社内のルールと規約で確かめます。書くのはAI、定義と検算は人、と分けておくと、AIのSQLを安心して業務に使えるようになります。



-160x90.png)




