本文将介绍如何通过MLSQL将一条又长又复杂(子查询,Join以及重复片段满天飞)的SQL简化成萌新都能看懂的SQL语句。
案例来了
下面一条SQL是从网上随便找的,大家可以看到,这条SQL结构上从结构上具备复杂化的潜质,子查询,Join等用的不亦乐乎。然而和真实的业务场景里的SQL复杂度比前来,这条SQL的复杂度简直是孙子级别的。
如果我们仔细思考下,我们至少发现两点:
- 这条SQL语句嵌套比较多,也就是里面有不少子查询以及join(union)查询。无论对于计算机还是人,嵌套分支其实都不是友好的,对人而言加大了理解难度,对机器而言会影响流水线并行。
- SQL里很多比较复杂的结构比如case when会重复的使用在同一条SQL语句的多个地方,你会惊讶的发现没有办法复用。
还有一点,数仓是有严格管理的,通常也有专业的团队维护,这意味着你并不能随心所欲在在数仓创建你经常用到的表。比如你经常会组合数仓中的A,B,C表得到一张表D,该表一般作为子查询使用。遗憾的是,你可能没办法很容易的去说服数仓团队帮你持久化D表。不得已,你可能需要有个小本本记住这条SQL,然后需要用的时候复制拷贝黏贴进你的业务SQL(大部分情况会作为子查询)。
因为当前大部分系统实现的SQL是以语句为单位的,多条SQL要联系起来,需要将表落地,而这个成本是比较高昂的,所以大家尽可能将一个功能需求在一条SQL中来完成,这又反向导致SQL变得很复杂。
现在,我们来用MLSQL来简化上面那条SQL。<u style="text-decoration: none; border-bottom: 1px dashed grey;">MLSQL</u> 是面向大数据和AI的一门语言,对SQL做了一定的增强,使得SQL更适用于脚本。
打平SQL,线性结构最符合大脑
首先,我们先把SQL展开,顺序化。在MLSQL中做法很简单,把子查询都摘录出来,然后在每个子查询语句的最后用分号来表示一条语句结束了。
在MLSQL Console里是这样的:
这个脚本是可以直接运行的,只需点击Run即可。
我们看到MLSQL允许你将一条条子查询独立出来,每条语句使用分号进行分割。其次,在后续语句中,你可以直接引用已经独立出来的子查询。进一步的,为了保持语法上的一致,MLSQL要求所有Select语句都需要以as TableName结尾。通过打平SQL语句,使得单条SQL复杂度有了很大的降低。
将多条SQL语句拆开成多个文件
创建a.mlsql, b.mlsql, main.mlsql 三个脚本。
其中a.mlsql为:
b.mlsql为:
main.mlsql:
可以看到,MLSQL支持inlclude语法,允许你将某些脚本包含到另外一个脚本中。在MLSQL最后的结果是这样:
这意味着,以后你要用a表,b表,你可以直接include对应的文件即可。
消除重复语句
我们发现下面两句非常重复,基本上意味着你必然会进行拷贝黏贴。
通过MLSQL我们可以进一步消消乐:
这里,我们通过set语法设置了一个模板,你会发现模板里有几个特殊的字符:
{0}
{1}
这个是参数占位符,他们分别会被第一个参数和第二个参数替换。对于语句:
${template.get("selectTemplate","a","b")}
系统首先会找到模板selectTemplate,然后用a替换{0},用b替换所有{1},最后语句会被渲染成:
a.player AS player , a.lose AS totallose, b.win AS totalwin, (totallose+totalwin) AS total
set语法也可以单独成一个文件,然后被其他语句引用。
最后成品:
可以看到,语句简化了非常多,而且更加易于阅读和复用,避免拷贝黏贴。
=========
欢迎大家关注我公众号 【祝威廉】