c++实现sqp优化_关于MySQL复杂需求实现

本文介绍了如何使用C++实现SQP优化来解决MySQL中的一个特殊SQL需求。需求涉及两个表W1和W2的复杂联接,通过LEFT JOIN和RIGHT JOIN结合窗口函数解决FULL OUTER JOIN的缺失数据问题,最终达到补全数据并获取所需结果集的目标。
摘要由CSDN通过智能技术生成

导读

作者:松华老师源码版本:MySQL 8.0.13


1fc604403a7222820d2d7db8582b7295.png

需求描述

这两天,开发人员提了一个比较特别的SQL需求,需求背景是:    字典表里没有记录,而实际的那张表里面有相应的记录。虽然可以直接在字典表中为每个组,加一行数据,但是我们无法判断加了这一行之后的影响范围。因此使用影响范围最小的方式,通过 SQL 查询出完整数据。

具体内容如下 : 

现在两个表W1和W2,表结构及数据情况如下:

 select * from w1;+------+------+------+| a    | b    | b1   |+------+------+------+| a    | b    | 0    || b    | b    | b1   || c    | b    | b2   || d    | b    | b3   || e    | c    | 0    || c    | c    | c1   |+------+------+------+6 rows in set (0.00 sec) select * from w2;+------+------+| b    | b1   |+------+------+| b    | b1   || b    | b2   || b    | b3   || b    | b4   || c    | c1   || c    | c2   || c    | c3   |+------+------+7 rows in set (0.00 sec)

想要得到的数据结果集如下:

+------+---+----+| a    | b | b1 |+------+---+----+| a    | b | 0  || b    | b | b1 || c    | b | b2 || d    | b | b3 || a    | b | b4 || e    | c | 0  || c    | c | c1 || e    | c | c2 || e    | c | c3 |+------+---+----+
1fc604403a7222820d2d7db8582b7295.png

步骤分析

表w1和w2 中,字段b的值为‘b’的记录分别有:

 select *from w1 where b='b';  +------+------+------+| a    | b    | b1   |+------+------+------+| a    | b    | 0    || b    | b    | b1   || c    | b    | b2   || d    | b    | b3   |+------+------+------+4 rows in set (0.00 sec) select *from w2 where b='b';+------+------+| b    | b1   |+------+------+| b    | b1   || b    | b2   || b    | b3   || b    | b4   |+------+------+4 rows in set (0.00 sec)

对以上部分记录的补全新需求,整理为:

表w1做主表, 补全表w2的数据部分, 补全部分数据为表w1的字段b1=0对应记录的字段a的值。

  • 补全结果集为:

+------+---+----+| a    | b | b1 |+------+---+----+| a    | b | 0  || b    | b | b1 || c    | b | b2 || d    | b | b3 || a    | b | b4 |+------+---+----+
  • 所补充的记录为:

+------+---+----+| a    | b | b1 |+------+---+----+| a    | b | b4 |+------+---+----+

从最终结果分析,首先需要基表w2 left join w1,关联条件为:w2.b=w1.b and w2.b1=w1.b1 ,结果如下;

->select w1.a ,w2.b,w2.b1 from w2 left join w1 on w2.b= w1.b and w2.b1=w1.b1;+------+------+------+| a    | b    | b1   |+------+------+------+| b    | b    | b1   || c    | b    | b2   || d    | b    | b3   || c    | c    | c1   || NULL | b    | b4   || NULL | c    | c2   || NULL | c    | c3   |+------+------+------+7 rows in set (0.00 sec)

但是,从结果上看少了两行,即 b1=0的部分。

此时,使用 full outer join 就可以 解决这个问题。

由于MySQL不支持full outer join,所以使用替代方案left outer join union right outer join 。

 select w2.b w2b , w2.b1 w2b1 ,w1.* from w2 left join w1 on w2.b= w1.b and w2.b1=w1.b1 union select * from w2 right join w1 on w2.b= w1.b and w2.b1=w1.b1;# 结果集如下:+------+------+------+------+------+| w2b  | w2b1 | a    | b    | b1   |+------+------+------+------+------+| b    | b1   | b    | b    | b1   || b    | b2   | c    | b    | b2   || b    | b3   | d    | b    | b3   || c    | c1   | c    | c    | c1   || b    | b4   | NULL | NULL | NULL || c    | c2   | NULL | NULL | NULL || c    | c3   | NULL | NULL | NULL || NULL | NULL | a    | b    | 0    || NULL | NULL | e    | c    | 0    |+------+------+------+------+------+9 rows in set (0.00 sec)

稍微美化一下SQL,结果如下:

 select       w3.a      ,case when w3.b is null then w3.w2b else  w3.b end b      ,case when w3.b1 is null then w3.w2b1 else  w3.b1 end b1 from (       select w2.b w2b , w2.b1 w2b1 ,w1.* from w2 left join w1 on w2.b= w1.b and w2.b1=w1.b1       union       select * from w2 right join w1 on w2.b= w1.b and w2.b1=w1.b1       )w3 order by b, b1;# 结果集如下:+------+------+------+| a    | b    | b1   |+------+------+------+| a    | b    | 0    || b    | b    | b1   || c    | b    | b2   || d    | b    | b3   || NULL | b    | b4   || e    | c    | 0    || c    | c    | c1   || NULL | c    | c2   || NULL | c    | c3   |+------+------+------+9 rows in set (0.00 sec)

现在我们离最终想要的结果集只差一步了,关于a 的空部分 ,有两种办法可以实现:

  1. 用标量子查询查一次表w1表求出对应的字段a

  2. 用窗口函数

1fc604403a7222820d2d7db8582b7295.png

实现方式

在本案例中,我们用窗口函数方法  max() over (partition by ):

 select w4.*,max(case when w4.b1='0' then w4.a end) over(partition by w4.b) m1 from (select           w3.a         ,case when w3.b is null then w3.w2b else  w3.b end b         ,case when w3.b1 is null then w3.w2b1 else  w3.b1 end b1       from (               select w2.b w2b , w2.b1 w2b1 ,w1.* from w2 left join w1 on w2.b= w1.b and w2.b1=w1.b1               union               select * from w2 right join w1 on w2.b= w1.b and w2.b1=w1.b1               ) w3       order by b , b1      ) w4;# 结果集如下:+------+------+------+------+| a    | b    | b1   | m1   |+------+------+------+------+| a    | b    | 0    | a    || b    | b    | b1   | a    || c    | b    | b2   | a    || d    | b    | b3   | a    || NULL | b    | b4   | a    || e    | c    | 0    | e    || c    | c    | c1   | e    || NULL | c    | c2   | e    || NULL | c    | c3   | e    |+------+------+------+------+9 rows in set (0.00 sec)

如上,已经得出了一个列m1。为了满足需求,我们下一步使用case when处理,就可以得出最终结果了,详情如下:

 select case when a is null then m1 else a end a       ,b       ,b1 from (       select   w4.*             ,max(case when w4.b1='0' then w4.a end ) over(partition by w4.b) m1       from (select                  w3.a                  ,case when w3.b is null then w3.w2b else  w3.b end b                ,case when w3.b1 is null then w3.w2b1 else  w3.b1 end b1              from (                      select w2.b w2b , w2.b1 w2b1 ,w1.* from w2 left join w1 on w2.b= w1.b and w2.b1=w1.b1                      union                      select * from w2 right join w1 on w2.b= w1.b and w2.b1=w1.b1                      ) w3              order by b , b1             ) w4      ) w5 ;# 结果集如下;+------+------+------+| a    | b    | b1   |+------+------+------+| a    | b    | 0    || b    | b    | b1   || c    | b    | b2   || d    | b    | b3   || a    | b    | b4   || e    | c    | 0    || c    | c    | c1   || e    | c    | c2   || e    | c    | c3   |+------+------+------+9 rows in set (0.00 sec)

至此,本次需求圆满满足。

       本案例中有两种实现方案,本文中仅使用了“窗口函数”方式实现需求。童鞋们可以自行尝试使用另外一种方法“标量子查询”完成 SQL。

        欢迎在评论区或者相关群里贴出各位的成果~~~ac904c9ed68300edd6c827d5ff0594f1.pngac904c9ed68300edd6c827d5ff0594f1.pngac904c9ed68300edd6c827d5ff0594f1.png

1fc604403a7222820d2d7db8582b7295.png

暖心贴士

松华老师历史好文回顾:

不用改表,老司机只用了这招提升千倍性能

SQL优化案例精彩连载(一)

实战演练(二):运行20小时的报表SQL优化后秒出

松华老师历史公开课回顾:

知数堂郑松华:MySQL 8.0 SQL优化之CTE 、窗口函数的应用

公开课发布《从50分到0.59秒,SQL优化让不可能变成可能》by松华

07e0f13b0dc12e5e0b963bd8e20a9331.gif

加入知数堂

挑战40万+年薪!

a188961f299d9c141f99e060ef71b55e.png4138767daa755fd1d1277ffa4419b613.pngef312b203916c3c1aa0f942221580698.png6b809538ee1806f782def44586fa7dc3.png

知数堂

叶金荣与吴炳锡联合打造

领跑IT精英培训

行业资深专家强强联合,倾心定制

MySQL的实战/ MySQL的优化/ MongoDB的/

Python / SQL优化/ Hadoop + ELK

数门精品课程

“阅读原文”可获更多正课试听视频

密码:hg3h

紧随技术发展趋势,定期优化培训教案

融入大量生产案例,贴合企业一线需求

社群陪伴学习,一次报名,可学1年

DBA,开发工程师必修课

上千位学员已华丽转身,薪资翻番,职位提升

改变已悄然发生,你还在等什么?

41554ac2547346c363b84d26fee2a7ab.png

a2185bc2deef59a97300a10c9ab228bc.gif

扫码加入QQ技术交流群

MySQL的入门到精通-ZST

  (QQ群号:793818397)    

629b78f6f38c1c64c2b0bdf06701aefa.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值