N 位开发者测完这个无幻觉 SQL 编译器,我们从中学到了什么
SQLazy刚完成后的一段时间,我们把它交给一批开发者,用他们自己的查询来试。
反馈整体是正面的,多数人上手就能把工作流跑通,编译出来的 SQL 直接拿去用了。被点名最多的是这几样:生成的 SQL 不瞎编字段、每一步都能点开看、以前不敢动的旧查询也能拿来重做。但痛点也收上来不少,有些还挺扎人。这些痛点不是一回事,我们分了两类看。
第一类:有些能力文档没讲清楚。比如只看重复行、不看唯一行这种取数需求,用去重功能的三个选项可以直接解决;判断一个值属不属于某个集合,用 contain 就行。这一类不用改代码,说清楚就够了。
第二类:能力够,但写起来绕。同一件事表达得出来,只是要绕一圈,或者读的人得盯着看才明白。我们从这一类反馈中学到的是:用户卡住的地方,往往不是功能做不到,而是写起来、读起来费劲。所以这一类我们动了手,下面几条是这一轮改得最值当的——每一处的改动看起来不大,解决的却是日常里反复出现的需求。
最值聚合:但并不要最值本身,而是要相关的其他属性
很多开发者都碰到过同一类麻烦:想要最值那条记录的另一个字段,比如最新那笔订单的金额。
SQL 里没有现成的一步写法,所以一般要写成子查询,先按客户找出最近日期,再回主表筛出来,顺手把聚合也做了:
SELECT ClientID, MAX(Amount) AS MaxAmt FROM orders o
WHERE OrderDate = (SELECT MAX(OrderDate) FROM orders WHERE ClientID = o.ClientID)
GROUP BY ClientID;
需要注意的是,最值对应记录可能不止一条,所以还要再做第二轮聚合,当然如果是单条再聚合一下也不会出错。
Oracle 等少数数据库能一步写完,靠的是专有的 KEEP 写法(MAX(Amount) KEEP (DENSE_RANK LAST ORDER BY OrderDate)),别的库没有,只能拆。
SQLazy 以前只能分两步:先筛出最新那天的记录,再对这批记录求最大:
t2=orders: rank OrderDate; max; partition ClientID
t3=t2: summarize max Amount; group ClientID
现在我们把这类需求统一简化成一句 SQLazy 代码:先求最值对应的那条或那些记录,再取另一个字段,
result= summarize argmax OrderDate max Amount; group ClientID
argmax 后面只跟一个值聚合:先按 OrderDate 锁定最新那天的记录(一条还是多条都行),再取其中最大的金额,一句写完,通用于一切数据库。
计算列:跨行指标从“算两次”到“一次搞定”
占比、累计这类跨行指标,以前没有专门处理,虽然能实现,但要用 2 次计算列功能,代码繁琐。
比如,对已经按销售员 SellerId 排序的 orders 表,要计算每笔订单在每个销售员的销售额中的占比。SQL 的常规写法是开窗(按分组开窗计算)一次算出总额再相除:
SELECT OrderID, Client, SellerId, Amount, OrderDate,
SUM(Amount) OVER (PARTITION BY SellerId) AS 销售员总额,
Amount / SUM(Amount) OVER (PARTITION BY SellerId) AS 金额占比
FROM orders;
以前 SQLazy 代码,要算两次,先算总额存一列,再相除:
t1 orders 计算列 合计, Amount, 命名 销售员总额; 分区 SellerId
t2 t1 计算列 Amount/销售员总额, 命名 金额占比
现在我们新加入了方便的跨行参数,SQLazy 代码只要一句——注意,这是我们补的,不是原来就有的:
t1 orders 计算列 Amount, 占比, 命名 金额占比; 分区 SellerId
新代码里“占比”就是跨行参数,一次算出每行占本组总额的比例,不用先算总额那一列。同理,累计、累计占比、增长率、同期比、同期增长等也都有对应的跨行参数,一句搞定。
我们学到的是:跨行指标人人都要算,绕的不是机器,是读代码的人。两步能写,但要先想明白中间那一列是干什么的。
分段、对齐、排名
分段依据可以有无穷多种,以前只能用条件表达式硬写——比如“值变了就分段”,要写成上一行比较加首行空值处理,读的人得在脑子里过一遍才确认。我们从中看到:分段依据看着无穷,常用的其实就那几种;所以我们把常用依据归纳成了八个枚举:变化、不变、变大、未变大、变小、未变小,另加总共分几组、每隔几条一组,把依据说出来就行。
报表要日期连续,没有数据的那天也要留一行。反馈让我们意识到,补空行绕的不是写法本身,而是三步之间还要交代对齐基准是哪一列。SQL 的常规做法是造一张日期序列再左关联回原表,SQLazy 以前也要先造序列再关联,两步;所以我们把这三步收进了一个 align,现在一句就能按基准对齐补空行,参数有对齐基准、只排序、保留其它列和分区。
取前几名这种需求天天见,以前却要先算出排名列(按某列排出先后名次)再筛一次,占两步;所以我们让 rank 直接按排名取,top、bottom 配计数,max、min 取记录。
这些改动为什么值当
AI writes the logic. A compiler writes the SQL.
这些改动都不大,落点却是同一类事:“按口径锁定一批记录再聚合”“算出这个分区里的占比和累计”“按业务依据分段”“把缺的日期补齐”“取前几名”——每一个都是每天都在发生的需求。改完之后,代码从绕着写变成一句话。
适用范围没变:简单增删改查直接写 SQL 更省事;宏还在路线图上,递归即将发布;上面这些能力也不是全部,我们改的只是反馈最集中的那几处。
SQLazy: Complex SQL, made lazy. Trusted by design.
欢迎把你测出来的坑贴到我们的论坛,AI 生成的、前人留下的都行。上面每一条,示例库里都有对应的真实难题github.com/SPLWare/SQLazy/tree/master/examples,提交自己的题会被拆解收录。
