ChatGPTでSQLを生成する

# はじめに
ErogameScapeには[SQLを学ぶためのページ](https://erogamescape.dyndns.org/~ap2/ero/toukei_kaiseki/sql_for_erogamer_index.php)があります。
これを学んで頂ければ、ErogameScapeのデータベースから必要な情報を自分で持ってこられると思っています。
しかし、それなりにハードルが高いので、取得してみたいデータはあるけど、SQLがわからないからデータを取得できない方もいらっしゃるのかなあと思っています、たぶん。

そこで、ChatGPTを使って自然言語からSQLを生成して、ErogameScapeからデータを取得できないだろうか、と思って試してみました。
具体的には```pg_dump DB名 -s```でダンプしたテーブル定義をそのまま食わせてから、例えば「brandlistテーブルからブランドの情報を取得するSQLを作成してください。」のように指示て正しいSQLが生成されるかどうかを試しました。

# 作ったもの
[批評空間用SQLAssistant](https://chat.openai.com/g/g-iptqeanC6-pi-ping-kong-jian-yong-sqlassistant)

:::note info
SQLは[こちら](https://erogamescape.dyndns.org/~ap2/ero/toukei_kaiseki/sql_for_erogamer_form.php)から実行できます。
:::

:::note alert
ChatGPT Plusでないと使えません(ChatGPTに課金していないと使えません)。
:::

# 分かったこと
## 情報としてテーブルのリレーションを渡す必要がある。
例えば「userreviewテーブルのgame列はgamelistのid列と対応している」という情報を渡す必要があります。
渡さなかった場合、外部キーがわからないので正しいSQLが生成されない確率が高いです。
事前にテーブル定義(```pg_dump DB名 -s```の出力)を与えていて、その定義に外部キーの情報も入っているのですが高い確率で外部キーを適切に判断することができません。

対処として[テーブル一覧](https://erogamescape.dyndns.org/~ap2/ero/toukei_kaiseki/sql_for_erogamer_tablelist.php)をKnowledgeに与えることにしました。具体的にはテーブル一覧を右クリックでhtmlとして保存して、そのままアップロードしました。
これでだいぶリレーションの情報を勝手に判断してくれるようになったのですが、ちょいちょい判断できないことがあります。

例えば以下のようなケースです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455288/19bdc184-d92e-0862-f686-9301a45f2cb9.png)

このクエリは間違っています。
gamelistとcreaterlistをくくりつけているのはshokushuテーブルなので**テーブル"public.createrlist"とテーブル"public.gamelist"を結びつけているのはテーブル"public.shokushu"である**という情報を追加で与えます。
リレーションの情報さえ渡せば正しいSQLを生成してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455288/17e82898-cc9e-81d9-3fd4-d3624cc7cdf2.png)

## 事前情報として、ある列に格納されている情報が自然言語の表現だとどうなるかの対応を渡すと、いい感じに解釈してくれて自然な表現でもSQLを作成してくれる

[テーブル一覧](https://erogamescape.dyndns.org/~ap2/ero/toukei_kaiseki/sql_for_erogamer_tablelist.php)をKnowledgeに与えることで自然な表現でもSQLを作成してくれるようになりました。
例えば、

:::note info
2022年に発売されたゲームでユーザーにプレイされた数がもっとも多かった順から10個抽出する。
ついでにクリアをあきらめたユーザーの総数の情報も付け加える。
:::
というSQLを作成してもらいたい場合、pg_dumpの出力からは、プレイという情報、あきらめたという情報がどこに格納されているかわからないので、**ユーザーがプレイしたという情報はuserreviewテーブルのplayというbolean型の列に、あきらめたという情報は同じテーブルのgiveupというboolean型の列に格納されている**という指示を与える必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455288/c23b95bc-a582-5179-4dae-53b9167a70d6.png)

[テーブル一覧](https://erogamescape.dyndns.org/~ap2/ero/toukei_kaiseki/sql_for_erogamer_tablelist.php)をKnowledgeに与えることで、以下のように自然な表現で書いても、高い確率で正しいSQLを生成できるようになりました。

:::note warn
たまに正しくないSQLを生成するので、その場合は追加で指示をする必要があります。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455288/e8935bdd-727a-afd0-7b89-91a249cfedc6.png)

## 威力を発揮するのは集計
SQLで集計をする場合、CASE式を使います。自分はCASE式を書くのが面倒で嫌いです。
そんな面倒な集計、いい感じにCASE式を使って書いてくれます。
以下は、

:::note info
ゲーム名「クリミナルボーダー 3rd offence」にくくりつけられたpovをpovごとに出力するSQLを生成してください。
出力する項目は以下の通りとします。
povのid,povのtitle,rankがAの総数,rankがBの総数,rankがCの総数
並び順はくくりつけられたpovの総数の降順にしてください。
:::
という指示を与えた例です。
1つ目の回答はSQLを実行したらエラーになったので、そのエラーをそのまま貼り付けて正しいSQLを出力させています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455288/1cf57e50-fc66-76fb-06e6-b66e480763d2.png)

[テキストマイニングで探るエロゲー批評の昔と今](https://booth.pm/ja/items/4987804)では、年別のレビュー投稿数が掲載されています。年別のレビュー投稿数を出力するSQLを生成させてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455288/bdc0fab6-b247-b9b2-9054-46f9875e056e.png)

同人のエロゲーとは何かを与える必要がありましたが、いい感じにSQLを作成できました。

自分はWINDOW関数を使い慣れていないのでいつも四苦八苦するのですがWINDOWS関数が必要なケースもいい感じにSQLを作成してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455288/1f89455f-6305-12fa-c52d-b0438df39806.png)

# 感想
SQLをまったく学んだことがないという方には使えない気がしますが、簡単なSELECT文が発行できて、テーブルの定義を見ればどこに何が格納されるか理解できて、どうテーブルをJOINすればいいかが分かって、SQLでやりたいことがある方にとっては使えるかもしれないと思います。