告別手敲 SQL ?GPT-3 自動幫你寫

作者 | Brian Kane @SeekWell

編譯 | 伍杏玲

出品 | AI科技大本營(ID:rgznai100)

【導語】手寫業務 SQL 很繁瑣?GPT-3來幫你!本文作者通過手動輸入簡單的英文描述秒 Get 到 SQL 了。聽說 AI 又來搶開發者飯碗,一起來看看吧:

作爲分析師,我花費大量時間編寫 SQL 來回復各類業務問題,如簡單的客戶查詢問題“用戶X是否有正確的計劃”,評估 KPI,增長指標“上個月有多少用戶註冊,轉換爲付費用戶的百分比是多少”,預估問題“12 個月內我們將獲得多少收入”。

爲了讓我的工作更輕鬆,我儘量使用自動化來完成。儘管公司研發一些工具來幫助解決,但需要寫 SQL 代碼的話用當前工具很難自動化,GPT-3 來救駕!

GPT-3 是一種文本完成引擎,它接受輸入的文本並返回它認爲接下來會出現的文本。現在已經有很多人使用它根據指定說明來生成 HTML、CSS 等代碼。

由於我的大部分工作是寫 SQL,所以我希望通過簡單的英語描述語句,GPT-3 將這些語句轉爲 SQL 代碼。接着執行該 SQL,等待頁面返回結果。

對我來說,GPT-3 Instruct(仍處於beta版)比更通用的 GPT-3 引擎更有效果,GPT-3 Instruct(尤其是davinci-instruct)可讓你給出 GPT-3 響應的特定指令。下面我將詳細爲大家展示下一些示例,其中 gif 裏輸入問題由我生成,爲綠色,GPT-3 將其轉換爲SQL(由GPT-3生成,爲藍色),我對 GPT-3 說明(黃色)和 GPT-3 示例(橙色)。

這是我給的第一條指令,一個問題以及GPT-3的回覆:

說明:給定輸入問題,請使用語法正確的 PostgreSQL 進行響應。可以有創新,但 SQL 必須正確

輸入:how many users signed up in the past month?

GPT-3:

SELECT COUNT(*) FROM users
WHERE signup_time > now() - interval '1 month'

我沒給過數據庫架構,但假設我有一個名爲“ users”的表,有“ signup_time”時間戳字段用於用戶註冊,這個符合邏輯。它知道在 PostgreSQL 中從今天的日期減去一個月的正確方法(now()-間隔“ 1個月”)。太酷了!

爲了給 GPT-3 提供更多的上下文,我將有關數據庫模式的信息添加到指令中。我的新指令:

說明:給定輸入問題,請使用語法正確的PostgreSQL進行響應。僅使用“用戶”和“收費”的表。“用戶”表具有以下列:id(整數),signup_dt(時間戳),電子郵件(字符變化)和plan_type(字符變化)。“費用”表中包含列:金額(bigint),user_id(整數)和charge_dt(時間戳)。

我問另一個問題,看看 GPT-3 是否可以根據實際數據庫來響應:

輸入:how much revenue did we have in the past 7 days?

GPT-3:

SELECT SUM(amount) FROM charges WHERE charge_dt > now() - interval '7 days'

我向它提供了有關數據庫中表和列的更多信息,它正確地推斷出“ amount” =“ revenue”,並 SUM()來統計 7 天收費後的金額,我們看到,它已知道一些基本的SQL語法,並推斷出我的意思。

用示例啓動GPT-3

我想需要通過一個簡單的示例來明確告知 GPT-3 表中的列,示例是提供 GPT-3上下文並充實一些細節的好方法,這有助於確定哪些列和表可以使用(GPT-3有時喜歡“發明”列)。這是我添加到提示中的示例:

輸入:select all available columns from users table.

輸出:

SELECT id, signup_dt, email, plan_type FROM users

輸入:select all available columns from charges table.

輸出:

SELECT amount, user_id, and charge_dt FROM charges

 將這些示例提供給 GPT-3,我將再問一個問題:

輸入:what was the largest payment amount made in the past 30 days?

GPT-3:

SELECT MAX(amount) FROM charges WHERE charge_dt > NOW() - INTERVAL '30 days'

它知道使用MAX(金額)來獲得最大的付款並正確設置日期條件,沒看到有關如何從當前日期減去天數的示例。我們再試試其他的:

輸入:when did user with email [email protected] make his last payment?

GPT-3:

SELECT MAX(charge_dt) FROM charges WHERE user_id = 1 AND email = '[email protected]'

不太對,“收費”表中沒有電子郵件列,因此該查詢將失敗。我也從來沒有說過電子郵件=“ [email protected]”的用戶的user_id = 1-不知道從何而來。要正確回答該問題,必須將“收費”表與“用戶”表結合在一起,因爲只有“用戶”有電子郵件列。

由於知道在users.id = Charges.user_id上聯接這些表是一個大的進步,所以我將給 GPT-3 一個“聯接”的示例:

輸入:when did [email protected] make her first payment?

輸出:

SELECT MIN(charge_dt) as last_payment_dt from charges LEFT JOIN
users ON users.id = charges.user_id
WHERE users.email = '[email protected]'

我再試一次:

輸入:when did user with email [email protected] make his last payment?

GPT-3:

SELECT MAX(charge_dt) as last_payment_dt from charges LEFT JOIN users ON users.id = charges.user_id WHERE users.email = '[email protected]'

根據示例,它變得太簡單了,它正確地更改了MIN()→MAX()並用我要求的電子郵件替換了該電子郵件。我們嘗試另一個難度級別,先加更多示例來提供更多背景信息並改善響應。新的例子:

輸入:how many users signed up in the past 30 days?

輸出:

SELECT COUNT(*) FROM users WHERE signup_dt >= now() - interval '30 days'

輸入:when did user with email [email protected] sign up?

輸出:

SELECT signup_dt FROM users WHERE email = '[email protected]'

輸入: how much revenue did we have in the past 7 days?

輸出:

SELECT SUM(amount) from charges WHERE charge_dt >= now() - interval '7 days'

輸入:how much revenue did we have from 10-01-20 through 11-15-20?

輸出:

SELECT SUM(case when charge_dt>= '10-01-20'::date and charge_dt < '11-15-20'::date then amount else 0 end) as revenue
FROM charges

輸入:how much revenue have we had from users that signed up in the last 6 months?

輸出:

SELECT SUM(charges.amount) FROM users INNER JOIN
charges ON users.id = charges.user_id
WHERE users.signup_dt>= now() - interval '6 months'

輸入:when did user with email [email protected] make his first payment?

輸出:

SELECT MIN(charge_dt) as last_payment_dt from users INNER JOIN
charges ON users.id = charges.user_id
WHERE users.email = '[email protected]'

輸入:how many new users signed up in each of the last 2 months?

輸出:

SELECT sum(case when signup_dt>= now() - interval '1 month' then 1 else 0 end) as signups_this_month,
sum(case when signup_dt>= now() - interval '2 months' and signup_dt < now() - interval '1 month'  then 1 else 0 end) as signups_last_month
FROM users

這些示例爲它提供了一些基本查詢,因此它更加熟悉我的數據庫以及用例的特定術語和概念(例如,“付費用戶”表示其plan_type =“ pro”)。我還介紹了彙總兩個日期之間的指標(收入)。我們繼續加深難度:

輸入:how many payments has user with email [email protected] made?

GPT-3:

SELECT COUNT(*) FROM users INNER JOIN  charges ON users.id = charges.user_id WHERE users.email = '[email protected]'

GPT-3認爲這裏的COUNT()是適當的表達式,知道將“用戶”與“收費”表結合在一起,並將電子郵件正確設置爲我所詢問的電子郵件。GPT-3的另一個問題:

輸入:how much revenue have we received from users with an email ending in 'seekwell.io' in the last 3 months?

GPT-3:

SELECT SUM(charges.amount) FROM users INNER JOIN charges ON users.id = charges.user_id WHERE users.email LIKE '%seekwell.io%' AND users.signup_dt>= now() - interval '3 months'

太棒了,它知道將“以seekwell.io結尾的電子郵件”在SQL中轉換爲“ users.email LIKE'%seekwell.io%'”(即使之前從未見過),並對與此匹配的用戶收取了所有費用的總和健康)狀況。還有一個:

輸入:how much revenue did we have between June 1st and August 1st 2020?

GPT-3:

SELECT SUM(case when charge_dt >= '06-01-2020'::date and charge_dt < '08-01-2020'::date then amount else 0 end) as revenue FROM charges

我已經教過它如何從10-01-20到11-15-20來獲取收入,所以它要容易一些,它確實知道將6月1日和8月1日轉換爲SQL中適當的日期格式('06- 01-2020”和“ 08-01-2020”)。如果它只是用“ 6月1日”和“ 8月1日”替換了我示例中的日期,我它不是在獲取日期的概念,只是將模式匹配到最接近的示例。有了這個結果,我可以知道GPT-3至少在某種程度上瞭解了日期的概念。

將 GPT-3 “玩壞了”

剛纔我列舉的例子都是關於用戶、收入和增長指標等基本問題,GPT-3 處理得很好。現在我想知道有多少用戶轉換爲付費用戶:

輸入:what percent of users who signed up converted to paid?

GPT-3:

SELECT COUNT() as total_users, COUNT() as total_paid_users, 100.0*(COUNT() as total_paid_users) / COUNT() as total_users AS percent_converted FROM users

這不是我想要的,絕對不是正確的SQL。它不理解“百分比”的概,它僅是 COUNT()並乘以100。我使用“百分比”來試驗下:

輸入:what percent of users have an email ending in 'gmail.com'?

輸出:

SELECT SUM(CASE WHEN email like '%gmail.com' then 1 else 0 end)/COUNT(*) as percent_gmail
FROM users

當我嘗試相同的問題時,我得到:

輸入:what percent of users who signed up converted to paid?

GPT-3:

SELECT SUM(CASE WHEN plan_type = 'pro' THEN 1 else 0 end)/COUNT(*) as percent_paid FROM users

整潔多了,它知道將plan_type ='pro'的用戶數除以用戶總數即可得到我要求的百分比。我還可以向部分用戶(例如最近6個月內註冊的用戶)詢問相同的問題,並獲得準確的答覆:

輸入:what percent of users that signed up in the past 6 months converted to paid?

GPT-3:

SELECT SUM(CASE WHEN plan_type='pro' THEN 1 ELSE 0 END)/COUNT(*) AS percent_paid FROM users WHERE users.signup_dt>= now() - interval '6 months'

調整 GPT-3 的參數

除了給GPT-3提供指導和示例外,還可以調整參數來提高 GPT-3 的有效性。其中關鍵要素是“Temperature”,它轉化爲GPT-3在響應中包含多少隨機性。如果只需要最高的概率響應(即無隨機性),則將 Temperature 設置爲0。

以“最近兩個月的每個月我們有多少收入?”提示爲例,將Temperature 設置爲.8的話:

輸入: how much revenue did we have in each of the last 2 months?

Temperature爲.8時 GPT-3:

SELECT SUM(case when charge_dt>= now() - interval '1 month'  then charges.amount else 0 end) as revenue_this_month, CASE WHEN signup_dt>= now() - interval '2 months' AND signup_dt < now() - interval '1 month' THEN SUM(charges.amount) else 0 end as revenue_last_month FROM charges  LEFT OUTER JOIN users ON users.id = charges.user_id \ WHERE users.signup_dt >= now() - interval '1 month'

將Temperature 設置爲較低的.3,可提供一個有效的查詢,並回答以下問題:

輸入:how much revenue did we have in each of the last 2 months?

Temperature爲.3時 GPT-3:

SELECT SUM(case when charge_dt>= now() - interval '1 month' then amount else 0 end) as revenue_this_month, SUM(case when charge_dt>= now() - interval '2 months' and charge_dt < now() - interval '1 month' then amount else 0 end) as revenue_last_month FROM charges

更高的Temperature 讓 GPT-3  變得更具“創造力”,但也使它過於複雜並給出了幾乎沒有意義的響應。Temperature 設置爲.3,響應將問題正確轉換爲SQL。

根據我的經驗,如果你問的問題遵循的是示例所建立的模式,則較低的Temperature往往會表現得更好。但是,如果您要問一些需要更多創造力的問題,則更高的Temperature是最佳選擇,因爲GPT-3更有可能嘗試未明確教導的事情。

在下面的案例中,我問:“過去6個月內註冊的用戶給我們帶來了多少收入?” (從我的示例中刪除之後)。在較低的Temperature下,GPT-3嘗試在“ charges”表中創建一個“ signup_dt”列,因此不必將“ users”表和“ charges”表連接在一起。隨着 Temperature 的升高,它確實加入了,這是Temperature設置爲.8的響應:

輸入:how much revenue have we had from users that signed up in the last 6 months?

Temperature爲.8時 GPT-3:

SELECT SUM(charges.amount) FROM users INNER JOIN charges ON users.id = charges.user_id WHERE signup_dt >= DATE_SUB(now(), INTERVAL '6 months')

可以肯定的是,“ DATE_SUB(now(),INTERVAL'6 months')”不是一個有效的Postgres表達式,因此該查詢在技術上將失敗。但是從結構上講,它通過加入“ charges”和“ users”而處於正確的道路上,因此可以以“ signup_dt”爲條件。同時,使用“ charges”表中實際上不存在的“ signup_dt”列,.Temperature設置爲.2時響應完全不正確:

輸入:how much revenue have we had from users that signed up in the last 6 months?

Temperature爲.2時 GPT-3:

SELECT SUM(CASE WHEN signup_dt >= now() - interval '6 months' THEN amount ELSE 0 END) AS revenue FROM charges

結論

GPT-3 實例會根據簡單的英語問題,將其轉換爲數據庫真正有效的SQL。它不總是完美,對“增長率”或“百分比”等複雜的概念仍然需要一些人工幫助,但是它對我的日常工作是有用,對於簡單的SQL,GPT-3 能幫忙減輕我的負擔,並且對於不熟悉 SQL 語法的初學者很有用。

這個項目的代碼傳送門:https://github.com/bkane1/gpt3-instruct-sandbox

原文鏈接:https://blog.seekwell.io/gpt3

本文爲AI科技大本營翻譯,轉載請註明來源出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章