PapillonのText-to-SQLは、SQLを書く前に何を読んでいるか
木村 優志
「先月の売上を商品カテゴリ別に出して」と入力すると、AIがSQLを書き、グラフにする。Text-to-SQLはこの体験を可能にします。
ただし、ここで本当に難しいのはSQLの構文ではありません。
amountは税込なのか、割引後なのか。created_atは注文日時なのか、データを登録した日時なのか。キャンセルはどの値で判別するのか。ordersとorder_itemsのどちらを基準に集計すべきか。
これらを理解せずに生成したSQLは、実行できたとしても業務の数字になりません。
開発中のBIツール「Papillon」では、LLMに自然言語の質問だけを渡すのではなく、接続先から得たスキーマと、必要に応じてセマンティックモデルを渡してSQLを生成します。本記事では、PapillonのText-to-SQLが何を入力としているのか、そして精度を上げるためにどこを整えるべきかを紹介します。
Papillonは開発中のソフトウェアです。ここで紹介する実装・設計は2026年8月18日時点のものであり、今後変更する可能性があります。
Text-to-SQLは「質問をSQLに翻訳する」だけではない
Text-to-SQLを単純化すると、次の流れです。
質問 + データ構造 + 指標の定義 → SQL 質問だけでは、SQLは決まりません。
たとえば「月次売上」を求める場合、モデルには少なくとも次を判断する材料が必要です。
- どの表に金額があるか
- どの日付を月でまとめるか
- キャンセルや返品をどう除外するか
- 注文と明細を結合して二重計上しないか
- 結果をカテゴリ、顧客、地域のどの単位で分けるか
LLMがそれらを一般知識から推測すると、実際のデータベースでは簡単に外れます。Papillonの設計では、推測に任せる範囲を減らし、SQLを作るための情報を先に組み立てます。
Papillonが最初に読むのは、接続先のスキーマ
ユーザーがText-to-SQLを実行すると、Papillonはまず接続中のデータソースを検査し、テーブル、列、型、主キー、外部キーを取得します。
対応している接続先はDuckDB、PostgreSQL、MySQL、Redshift、Snowflake、BigQueryです。同じ質問でもSQL方言が異なるため、接続先の方言も生成時の入力に含めます。
取得したスキーマは、そのまま大きなJSONとして渡しません。Papillonでは、次のような短い形式へ整形します。
public.orders(order_id bigint, customer_id bigint, ordered_at timestamp, status varchar)
public.order_items(order_id bigint, product_id bigint, amount decimal)
public.products(product_id bigint, category varchar, name varchar) この形なら、LLMは使える表と列を確認しながらSQLを書けます。実装ではスキーマの文字数に上限を設け、上限を超えた場合は途中で打ち切ります。
全スキーマを無制限に渡す方が正確そうに見えるかもしれません。しかし、テーブル数が多い環境では、関係ないステージング表や履歴表まで候補になり、かえって選択を誤りやすくなります。コンテキストには限りがあるため、LLMに渡す情報は多さではなく、質問との関係で設計する必要があります。
スキーマから得られるのは、事実と「ヒント」
Papillonは、列名と型から、SQL生成に役立つヒントも組み立てます。
- 同じ形のID列から、結合候補を推測する
name、title、categoryなどを、人が読めるラベルの候補として扱う- 金額らしい文字列列には数値への変換が必要かもしれないと示す
- 日付・時刻らしい列には、日付関数の前に変換が必要かもしれないと示す
たとえば、order_items.product_idとproducts.product_idがあれば、商品名やカテゴリを出すにはproductsを結合する可能性があります。グラフの横軸に内部IDだけを使わず、カテゴリや商品名のようなラベルを選ぶことも、可視化にとって重要です。
ただし、これは確定情報ではありません。同じ名前の列があっても、必ず正しく結合できるとは限りません。Papillonの生成指示でも、こうしたヒントは検証すべきものとして扱っています。
それでも、スキーマだけでは「売上」を定義できない
スキーマは「どんな列があるか」を教えてくれますが、「会社で何を売上と呼ぶか」は教えてくれません。
次の二つは、どちらも実行できるSQLです。
SELECT DATE_TRUNC('month', ordered_at), SUM(amount)
FROM order_items
GROUP BY 1; SELECT DATE_TRUNC('month', o.ordered_at), SUM(i.amount)
FROM orders AS o
JOIN order_items AS i ON i.order_id = o.order_id
WHERE o.status = 'completed'
GROUP BY 1; しかし、前者はキャンセル済みの明細を含むかもしれません。後者も、返品や割引、税の扱いまで正しいとは限りません。
この差を埋めるための層が、Papillonのセマンティックモデルです。
セマンティックモデルは、組織の言葉をデータへ結び付ける
Papillonのセマンティックモデルでは、フィールド、メトリクス、結合、階層を定義できます。
- ディメンション:商品カテゴリ、地域、顧客区分、月など、分析の切り口
- メトリクス:売上、注文件数、平均単価など、集計したい数値
- 結合:どの表を、どのキーで結び付けるか
- 階層:年→四半期→月のように、分析を掘り下げる順序
モデルには、下書き、公開済み、認定済み、廃止といった状態も持たせられます。単にLLMのための補助データではなく、チームで指標の正本を管理するための土台です。
Text-to-SQLを実行すると、Papillonは利用できるセマンティックモデルがある場合、スキーマ要約の後ろへそのモデルのディメンションとメトリクスを追加します。そして、質問を満たせるなら、名前付きのセマンティックメトリクスとディメンションを優先するよう指示します。
ここで重要なのは、AIに「売上とは何か」を毎回プロンプトで説明しないことです。セマンティックモデルとして一度定義し、SQL、ダッシュボード、AIへの質問で同じ言葉を使えるようにします。
生成されたSQLに対して、Papillonがしている制約
PapillonのText-to-SQLは、任意のSQLを返すのではなく、1本の読み取り専用SELECT文を生成する前提です。
生成の指示には、次のような制約があります。
- 渡されたスキーマにある表と列だけを使う
- 集計しない列を選択するなら、適切に
GROUP BYする - 結合では、列を所有する表の別名を明示する
SELECT *ではなく、必要な列を明示する- グラフの軸に内部IDだけを置かず、人が読めるラベルを優先する
- 接続先のSQL方言に合わせる
返却されたSQLは、余計なMarkdownや複数文を取り除き、方言に応じた補正をしてから、読み取り専用SQLとして検証されます。
これは正しい業務ロジックを保証する仕組みではありません。しかし、存在しない列を使う、GROUP BYが足りない、意図せず更新する、といった基本的な失敗を減らすための層です。
精度を上げるために、最初に整えるべきもの
Text-to-SQLが期待どおりに動かないとき、すぐにモデルを替える必要はありません。まず、LLMへ渡している情報を確認する方が効果的です。
1. 表と列の名前
a01やitem_flgのような名前しかないと、LLMも人間も意味を判断しにくくなります。既存DBの列名をすぐ変更できない場合は、セマンティックモデルで表示名と説明を与えます。
2. 結合と粒度
最も危険なのは、結合で行数が増え、金額や件数が水増しされることです。主キー・外部キーを取得できるようにし、集計の基準が注文、明細、顧客のどれかを定義します。
3. メトリクスの定義
「売上」「アクティブユーザー」「解約率」は、会社ごとに定義が違います。除外条件、分母、対象期間を、認定済みのメトリクスとして管理します。
4. 値の表記
statusの値がcompletedなのか確定なのか、1なのかは、型だけでは判断できません。LLMへ実データを大量に渡す前に、区分値とその意味を定義側へ残す方が安全です。
5. 評価ケース
「先月の確定売上」「地域別の受注件数」のような、実務で繰り返す質問を用意し、期待するSQLまたは数値と比較します。評価ケースがあれば、プロンプトやモデルを変えたときに、改善したのかを判断できます。
AIが出したSQLを、誰が確認するか
Text-to-SQLは、分析を始める速度を上げます。しかし、最終的な数字の責任までAIへ移すものではありません。
特に、経営会議、請求、顧客向けレポートで使う数字は、次を確認する必要があります。
- 集計の粒度は合っているか
- 結合による重複計上がないか
- 日付列とタイムゾーンの扱いは正しいか
- キャンセル、返品、テストデータを除外できているか
- セマンティックモデルの認定済みメトリクスを使っているか
PapillonはSQLワークスペース、可視化、セマンティックモデルを同じ製品内に置くことで、生成されたSQLをブラックボックスにせず、確認・修正・共有できる形を目指しています。
まとめ
PapillonのText-to-SQLで重要なのは、自然言語からSQLを出すモデルそのものだけではありません。
スキーマを短く整理し、結合やラベルのヒントを与え、業務上の定義をセマンティックモデルへ置き、読み取り専用のSQLとして検証する。この順番で、LLMの推測へ任せる範囲を小さくします。
Text-to-SQLは「質問すれば答えが出る」機能ではなく、データ構造と業務定義を整えることで、分析を速く、再現可能にするためのインターフェースです。Papillonでも、AI機能だけを先に増やすのではなく、チームが同じ数字を見られる土台を作っていきます。



