MySQL安装及应用合集(5):如何优雅地写MySQL

一、前言

关于代码的格式问题,其实这个也没有什么好说的,每个人都有不同的习惯,不能说我的方法好,你的方法不好,适合自己的就是最好的。
针对不熟悉的业务,我很喜欢去看相关业务的SQL逻辑,如果能够结合需求或者业务场景来理解,那自然再好不过,要是代码能再给点数据,就更完美了!之前看过了好些同事的SQL代码,有的写的特别的工整,看着特别舒服,当然,更多的是怎么方便怎么来,有时候看得我抓狂,之前看到一个最厉害的,一个逻辑从头写到尾,一行到底,关联了十来个表,子查询、and、where条件穿插其中,没有换行,一个逻辑一行到底这还是头一次见,当事人已经离职,不知道他后期维护是怎么做的,难以想象,哈哈哈。

今天推荐一个语法吧with as(),可以帮助我们写出比较优雅易看的数据。

二、with as语法及应用

这个语法其实是创建一个临时表,和子查询差不多,只不过它可以把代码单独拎出来,而不是放在fromjoin后面,导致整体看起来有很臃肿的感觉。有点像编程中的函数,把代码封装起来,然后直接调用表名,可以查找返回的字段。
举个小例子来看一下吧:
假设我有一个订单表,现在想看一下所有用户最近购买的订单金额和时间。
为了方便大家拿来就用,我把这些数据通过with as()创建一个临时表来调试,代码如下:

with 
orders as(
    select 100 as "user_id",'2022-07-01 10:11:33' as "payment_time",1240 as "paymnet_amount" union all
    select 101,'2022-07-01 11:35:12',1630 union all
    select 102,'2022-07-01 13:24:45',3304 union all
    select 103,'2022-07-01 16:44:59',1146 union all
    select 104,'2022-07-01 19:01:27',1895 union all
    select 103,'2022-07-11 16:44:59',2146 union all
    select 104,'2022-07-21 19:01:27',1095 union all
    select 104,'2022-08-01 19:01:27',3088 
)
-- 对orders订单进行排序
,orders_order_by as(
    select o.*
        ,row_number()over(partition by o.user_id order by o.payment_time desc) "last_pay_label"
    from orders o 
)
-- 取出最后一次付款的所有信息
select o.user_id,o.payment_time,o.paymnet_amount
from orders_order_by o
where o.last_pay_label=1;

如果是通过子查询,则是这样子:
看着似乎还可以,也不会很冗余。

with 
orders as(
    select 100 as "user_id",'2022-07-01 10:11:33' as "payment_time",1240 as "paymnet_amount" union all
    select 101,'2022-07-01 11:35:12',1630 union all
    select 102,'2022-07-01 13:24:45',3304 union all
    select 103,'2022-07-01 16:44:59',1146 union all
    select 104,'2022-07-01 19:01:27',1895 union all
    select 103,'2022-07-11 16:44:59',2146 union all
    select 104,'2022-07-21 19:01:27',1095 union all
    select 104,'2022-08-01 19:01:27',3088 
)
-- 取出最后一次付款的所有信息
select o.user_id,o.payment_time,o.paymnet_amount
from (
    -- 对orders订单进行排序
    select o.*
        ,row_number()over(partition by o.user_id order by o.payment_time desc) "last_pay_label"
    from orders o 
)o
where o.last_pay_label=1;

附上结果图:
image.png
小案例稍微升级一下,这次拿购买至少两次以上的用户最近两次购买的订单总金额和时间间隔。
with as实现则是:

with 
orders as(
    select 100 as "user_id",'2022-07-01 10:11:33' as "payment_time",1240 as "paymnet_amount" union all
    select 101,'2022-07-01 11:35:12',1630 union all
    select 102,'2022-07-01 13:24:45',3304 union all
    select 103,'2022-07-01 16:44:59',1146 union all
    select 104,'2022-07-01 19:01:27',1895 union all
    select 103,'2022-07-11 16:44:59',2146 union all
    select 104,'2022-07-21 19:01:27',1095 union all
    select 104,'2022-08-01 19:01:27',3088 
)
-- 对orders订单进行排序
,orders_order_by as(
    select o.*,row_number()over(partition by o.user_id order by o.payment_time desc) "last_pay_label"
    from orders o 
)
-- 分别取最后一次o1,和倒数第二次o2订单进行关联
select o1.user_id
    ,o1.paymnet_amount+o2.paymnet_amount "paymnet_amount"
    ,datediff(o1.payment_time,o2.payment_time) "time_diff"
from orders_order_by o1,orders_order_by o2 
where o2.user_id=o1.user_id 
and o1.last_pay_label=1
and o2.last_pay_label=2;

接下来再用子查询查一遍:


with orders as(
    select 100 as "user_id",'2022-07-01 10:11:33' as "payment_time",1240 as "paymnet_amount" union all
    select 101,'2022-07-01 11:35:12',1630 union all
    select 102,'2022-07-01 13:24:45',3304 union all
    select 103,'2022-07-01 16:44:59',1146 union all
    select 104,'2022-07-01 19:01:27',1895 union all
    select 103,'2022-07-11 16:44:59',2146 union all
    select 104,'2022-07-21 19:01:27',1095 union all
    select 104,'2022-08-01 19:01:27',3088 
)
select o1.user_id
    ,o1.paymnet_amount+o2.paymnet_amount "paymnet_amount"
    ,datediff(o1.payment_time,o2.payment_time) "time_diff"
from (
    -- 最后一次订单
    select o.*,row_number()over(partition by o.user_id order by o.payment_time desc) "last_pay_label"
    from orders o 
    ) o1
join (
    -- 倒数第二次订单
    select o.*,row_number()over(partition by o.user_id order by o.payment_time desc) "last_pay_label"
    from orders o 
    ) o2 on o2.user_id=o1.user_id 
where o1.last_pay_label=1
and o2.last_pay_label=2;

附上结果图:
image.png

通过以上两个小案例,或许可以感受到with as带来的一些好处。案例一比较简单,所以没有太大的区别,但是随着代码的复杂度提升,子查询会变得越来越“臃肿”,特别在几百上千行的代码中,经常看到select,看不到具体来自于哪一个表,需要来回反复查找。而通过with as可以更快定位到是哪一个表,然后往上找源表,相对来说会整洁而且模块化。另外一个重要的点是,在代码逻辑重复使用的时候,with as重新调一便表名即可,但是子查询需要原原本本复制以便,后期维护也麻烦,需要多出同时修改,如果不是原创者,这可能会成为一个实实在在的坑。

三、总结

总结一下,with as的语法三个优点:模块化、可复用、优雅整洁。
另外,代码必要的注释和空格/空行还是很需要的,可以让自己养一个好习惯,当然仁者见仁智者见智,喜欢便好。



- End -
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xin学数据

为你点亮一盏灯,愿你前进无阻。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值