告别手敲 SQL ?GPT-3 自动帮你写

2021-02-05 09:44:28 浏览数 (1)

作者 | 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:

代码语言:javascript复制
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:

代码语言:javascript复制
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.

输出:

代码语言:javascript复制
SELECT id, signup_dt, email, plan_type FROM users

输入:select all available columns from charges table.

输出:

代码语言:javascript复制
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:

代码语言:javascript复制
SELECT MAX(amount) FROM charges WHERE charge_dt > NOW() - INTERVAL '30 days'

它知道使用MAX(金额)来获得最大的付款并正确设置日期条件,没看到有关如何从当前日期减去天数的示例。我们再试试其他的:

输入:when did user with email brian@seekwell.io make his last payment?

GPT-3:

代码语言:javascript复制
SELECT MAX(charge_dt) FROM charges WHERE user_id = 1 AND email = 'brian@seekwell.io'

不太对,“收费”表中没有电子邮件列,因此该查询将失败。我也从来没有说过电子邮件=“ brian@seekwell.io”的用户的user_id = 1-不知道从何而来。要正确回答该问题,必须将“收费”表与“用户”表结合在一起,因为只有“用户”有电子邮件列。

由于知道在users.id = Charges.user_id上联接这些表是一个大的进步,所以我将给 GPT-3 一个“联接”的示例:

输入:when did jane@seekwell.io make her first payment?

输出:

代码语言:javascript复制
SELECT MIN(charge_dt) as last_payment_dt from charges LEFT JOIN
users ON users.id = charges.user_id
WHERE users.email = 'jane@seekwell.io'

我再试一次:

输入:when did user with email brian@seekwell.io make his last payment?

GPT-3:

代码语言:javascript复制
SELECT MAX(charge_dt) as last_payment_dt from charges LEFT JOIN users ON users.id = charges.user_id WHERE users.email = 'brian@seekwell.io'

根据示例,它变得太简单了,它正确地更改了MIN()→MAX()并用我要求的电子邮件替换了该电子邮件。我们尝试另一个难度级别,先加更多示例来提供更多背景信息并改善响应。新的例子:

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

输出:

代码语言:javascript复制
SELECT COUNT(*) FROM users WHERE signup_dt >= now() - interval '30 days'

输入:when did user with email brian@seekwell.io sign up?

输出:

代码语言:javascript复制
SELECT signup_dt FROM users WHERE email = 'brian@seekwell.io'

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

输出:

代码语言:javascript复制
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?

输出:

代码语言:javascript复制
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?

输出:

代码语言:javascript复制
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 brian@seekwell.io make his first payment?

输出:

代码语言:javascript复制
SELECT MIN(charge_dt) as last_payment_dt from users INNER JOIN
charges ON users.id = charges.user_id
WHERE users.email = 'brian@seekwell.io'

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

输出:

代码语言:javascript复制
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 joe@freshpizza.com made?

GPT-3:

代码语言:javascript复制
SELECT COUNT(*) FROM users INNER JOIN  charges ON users.id = charges.user_id WHERE users.email = 'joe@freshpizza.com'

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:

代码语言:javascript复制
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:

代码语言:javascript复制
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:

代码语言:javascript复制
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'?

输出:

代码语言:javascript复制
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:

代码语言:javascript复制
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:

代码语言:javascript复制
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:

代码语言:javascript复制
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:

代码语言:javascript复制
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:

代码语言:javascript复制
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:

代码语言:javascript复制
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科技大本营翻译,转载请注明来源出处。

0 人点赞