🚒

Phi-3でSQL生成を試す

2024/04/26に公開

やりたいこと

この記事を見て、日本語が苦手かもとあったので、日本語使わないタスクならできそうかで、SQL生成を試してみます。
https://zenn.dev/headwaters/articles/0d0e3db45c6559

期待としては、CodeGenerateがzeroshotだとそれなりに良さそうなのと、
SQL生成となると速度が求められがちなので、SLMなら回答生成速度早いのかなーと。

https://azure.microsoft.com/en-us/blog/introducing-phi-3-redefining-whats-possible-with-slms/

試す

Azure AI Playground

言語がenしか選べない。。

けど、適当に生成されたSQL生成のクエリを作成する.
サンプルプロンプト

次のように3つのテーブルが定義されています:
customers: 顧客情報を保存するテーブル。
customer_id (INT, 主キー): 顧客のユニークな識別子。
first_name (VARCHAR): 顧客の名。
last_name (VARCHAR): 顧客の姓。
orders: 顧客によって配置された注文を記録するテーブル。
order_id (INT, 主キー): 注文のユニークな識別子。
customer_id (INT): 注文をした顧客の識別子。
order_date (DATE): 注文が行われた日付。
total_amount (DECIMAL): 注文の合計金額。
order_items: 各注文に含まれるアイテムを含むテーブル。
item_id (INT, 主キー): アイテムのユニークな識別子。
order_id (INT): このアイテムを含む注文の識別子。
product_name (VARCHAR): 製品名。
quantity (INT): 注文された製品の数量。
price (DECIMAL): 製品の価格。

これらの三つのテーブルを結合して、各顧客ごとに注文された製品の合計数量と合計金額を見つけるSQLクエリを作成してください。
結果には顧客の名、姓、計算された合計が含まれるべきです。結果を顧客ごとにグループ化し、合計金額で降順に並べ替えてください。

出力

SELECT 
   c.first_name,
   c.last_name,
   SUM(oi.quantity) AS total_quantity,
   SUM(oi.quantity * oi.price) AS total_amount
FROM 
   customers c
JOIN 
   orders o ON c.customer_id = o.customer_id
JOIN 
   order_items oi ON o.order_id = oi.order_id
GROUP BY 
   c.customer_id
ORDER BY 
   total_amount DESC;

サンプルプロンプト作成時に作成された、正解SQL

SELECT   
    c.first_name,   
    c.last_name,   
    SUM(oi.quantity) AS total_quantity,   
    SUM(oi.price * oi.quantity) AS total_amount  
FROM customers c  
JOIN orders o ON c.customer_id = o.customer_id  
JOIN order_items oi ON o.order_id = oi.order_id  
GROUP BY c.customer_id  
ORDER BY total_amount DESC;  

同じだ!

もうちょっと難しいのを生成してみる。
サンプルテキスト

以下の4つのテーブルがあるとします:
customers: 顧客情報を保持するテーブル。
customer_id (INT, 主キー): 顧客を一意に識別するID。
first_name (VARCHAR): 顧客の名前。
last_name (VARCHAR): 顧客の姓。
orders: 注文情報を保持するテーブル。
order_id (INT, 主キー): 注文を一意に識別するID。
customer_id (INT): 顧客IDを参照する外部キー。
order_date (DATE): 注文日。
status (VARCHAR): 注文の状態(例:'completed', 'pending'など)。
order_items: 注文された各アイテムを保持するテーブル。
item_id (INT, 主キー): アイテムを一意に識別するID。
order_id (INT): 注文IDを参照する外部キー。
product_id (INT): 製品IDを参照する外部キー。
quantity (INT): 注文された数量。
products: 製品情報を保持するテーブル。
product_id (INT, 主キー): 製品を一意に識別するID。
product_name (VARCHAR): 製品名。
price (DECIMAL): 製品の単価。

'completed'ステータスの注文に関連する製品の総売上と総利益(総売上から総コストを引いた値)を計算するSQLクエリを作成してください。
総売上は、各製品のpriceとquantityを掛け合わせた値の合計です。
総コストは、各製品のコスト(ここでは簡単のためpriceの半分とします)とquantityを掛け合わせた値の合計です。
結果には製品名、総売上、総利益を表示し、総売上の高い順に並べてください。

回答

SELECT 
   p.product_name,
   SUM(oi.quantity * oi.price) AS total_sales,
   SUM((oi.quantity * oi.price) - (oi.quantity * (oi.price / 2))) AS total_profit
FROM 
   orders o
JOIN 
   order_items oi ON o.order_id = oi.order_id
JOIN 
   products p ON oi.product_id = p.product_id
WHERE 
   o.status = 'completed

良さげだけど、途中でキレてる。。

サンプルプロンプトを作成時に作成された、正解SQL

SELECT   
    p.product_name,   
    SUM(oi.quantity * p.price) AS total_sales,  
    SUM(oi.quantity * p.price) - SUM(oi.quantity * (p.price / 2)) AS total_profit  
FROM orders o  
JOIN order_items oi ON o.order_id = oi.order_id  
JOIN products p ON oi.product_id = p.product_id  
WHERE o.status = 'completed'  
GROUP BY p.product_name  
ORDER BY total_sales DESC;  

max_tokensを256にして、もう一回。

出力

SELECT 
 p.product_name,
 SUM(oi.quantity * p.price) AS total_sales,
 SUM(oi.quantity * (p.price / 2)) AS total_cost,
 SUM(oi.quantity * (p.price - (p.price / 2))) AS total_profit
FROM 
 orders o
JOIN 
 order_items oi ON o.order_id = oi.order_id
JOIN 
 customers c ON o.customer_id = c.customer_id
WHERE 
 o.status = 'completed'
GROUP BY 
 p.product_name
ORDER BY 
 total_sales DESC;

なぜか、total_costを余計に出してくれたけど、おおむね良さそう。

あと、期待通り回答生成時間が早いです。全部生成されるまで、2.6秒とかでした。

複雑なSQLを書くならfewshotである必要があると思いますが、zeroshotだと結構使えるかも。

ヘッドウォータース

Discussion