场景再现
废话不多说,我们来感受一下一个场景。假设我现在想查询一个表的重复数据,也就是我们经常所说的查询有重复记录的数据,那我该如何写语句呢?
查询含有重复项的数据
以上语句,having一般和group by一起用,本语句是先分组,对每组结果各自进行count(user_id)。那再试想一下,那如果我想要去重,找到ID较小的那条记录展示并用于后续执行删除呢?是不是就要子查询帮忙了。答案是肯定的。子查询可以解决简单查询无法完成的复杂逻辑查询,小马曾经就写过上百行的一个SQL查询语句,当然这是不被建议的,只是当时数据表设计的缺陷问题,不得已而为之,也算是权宜之计。那么子查询到底能多疯狂呢?下面就一起来感受一下。
什么是子查询
什么是子查询?这里我们可以通俗地理解为,子查询就是将一个查询(子查询)的结果作为另一个查询(主查询)的数据来源或判断条件的查询。这句话很好理解,就是有一个子查询被作为另一个主查询的数据来源或判断条件。常见的类型有WHERE子查询,HAVING子查询,FROM子查询,SELECT子查询,EXISTS子查询。
首先我们来创建一个表结构student表,然后插入若干数据。
student表结构
下面我们就来看看这几种类型的不同应用。
五种类型的子查询
上面是按照五种类型以此展示的含子查询语句案例。第一个查询语句取分数低于平均分的学生;第二个查询语句取平均分+20能大于最高分的职位并同时输出其平均分是是多少;第三个查询语句查询平均分数高于25的职位以及显示该职位的平均分数;第四个查询语句查询职位是组长的学生人数占总学生人数的比例;第五个查询语句查询有住宿信息的学生。怎么样,子查询是不是很万能,感受到它的疯狂了吗?这里只是简单的示例,当然还能根据业务组合出更加复杂的查询逻辑。
以下附上上面5个语句查询的结果展示。
WHERE子查询
HAVING子查询
FROM子查询
SELECT子查询
项目实战
练兵之后,我们就该上实际项目实践以下了。来实战一个比较复杂的需求:我现在有一个分享功能,DB需要记录用户每次的分享详细数据,如果用户当天有分享则可以结算一次积分,注意每天可以分享无限次但只能结算一次。于是我们的DB设计:
tbShare表
现在我们的需求来了,我想查询用户openid为1的每日分享结算情况?怎么查询呢?
那如果要获取已结算的总数或者总天数呢?
我想要查询用户openid为1的一条最早的未结算的分享数据来进行结算,怎么取呢?
好了,是不是已经掌握到技巧了,其实万变不离其宗。我们说其实子查询语句的效率不一定就好,那么假如不需要用户具体的每日分享详细时间数据,只需要知道每日分享总次数,我们可以怎么改造DB设计使其避免进行子查询呢?以下是改造后的DB供参考,至于为什么更好呢,改造后逻辑又是怎么实现,可以先自行思考哈。
关于SQL语句的子查询就到这了,欢迎评阅和交流。