Mysql 特殊操作场景
分组后查询前几条
示例背景:
建表语句
CREATE TABLE `aaaa`
(
`EPI_AUTOID` int(10) NOT NULL AUTO_INCREMENT COMMENT '唯一ID',
`EPI_UIFID` int(10) DEFAULT NULL COMMENT '用户ID',
`EPI_CNAME` varchar(50) DEFAULT NULL COMMENT '案例名称',
`EPI_DCREATEDT` datetime DEFAULT NULL COMMENT '创建时间'
PRIMARY KEY (`EPI_AUTOID`)
) ENGINE = InnoDB
AUTO_INCREMENT = 159
DEFAULT CHARSET = utf8 COMMENT ='个人案例';
表中数据
| EPI_AUTOID | EPI_UIFID | EPI_CNAME | EPI_DCREATEDT |
|---|---|---|---|
| 1 | 1 | 这是项目名1-1 | 2012-05-01 |
| 2 | 1 | 这是项目名1-2 | 2012-05-02 |
| 3 | 2 | 这是项目名2-1 | 2012-05-03 |
| 4 | 2 | 这是项目名2-2 | 2012-05-04 |
| 5 | 2 | 这是项目名2-3 | 2012-05-05 |
| 6 | 2 | 这是项目名2-4 | 2012-05-06 |
| 7 | 3 | 这是项目名3-1 | 2012-05-07 |
| 8 | 3 | 这是项目名3-2 | 2012-05-08 |
| 9 | 3 | 这是项目名3-3 | 2012-05-09 |
| 10 | 3 | 这是项目名3-4 | 2012-05-10 |
| 11 | 4 | 这是项目名4-1 | 2012-05-11 |
| 12 | 4 | 这是项目名4-2 | 2012-05-12 |
| 13 | 4 | 这是项目名4-3 | 2012-05-13 |
| 14 | 4 | 这是项目名4-4 | 2012-05-14 |
方式一:使用临时变量进行过滤
利用中间变量,判断是否和分组条件一致,一致则进行自增->产生中间临时表,最终查询时,根据自增数进行过滤,达到只展示前几条的目的
-- 查询语句如下
SELECT EPI_UIFID,EPI_CNAME,new_rank as rank from
(SELECT EPI_UIFID,EPI_CNAME,
-- 判断是否符合分组条件,如果当前数据的EPI_UIFID等于@tmp,则+1,否则初始化定义为1
IF(@tmp=EPI_UIFID,@rank:=@rank + 1,@rank:=1) as new_rank,
-- 声明临时变量,赋值EPI_UIFID=@tmp
@tmp:=EPI_UIFID as tmp
FROM aaaa
ORDER BY EPI_UIFID DESC) b
-- 模拟分组,取分组前3条数据
where new_rank <= 3;
需要关注的是,24行和26行的顺序不能颠倒。24行会先判断tmp是否和分组列相等,当未设置值时,会设置值为rank=1,后面26行会设置值tmp=EPI_UIFID;第二行执行时,此时tmp值已经更新为EPI_UIFID,所以判断为真,此时rank+1,达到顺序自增的效果
方式二:使用关联子查询进行过滤
关联子查询会引用外部查询中的一列或多列。这种子查询之所以被称为关联子查询,是因为子查询的确与外部查询有关。当问题的答案需要依赖于外部查询中包含的每一行中的值时,通常就需要使用关联子查询。
SELECT *
FROM aaaa m1
WHERE 3 > (
-- 关联子查询
SELECT COUNT(1)
FROM aaaa m2
WHERE m1.`EPI_AUTOID` > m2.`EPI_AUTOID`
AND m1.`EPI_UIFID` = m2.`EPI_UIFID`
)
ORDER BY m1.EPI_UIFID desc, m1.EPI_AUTOID desc;
执行原理就是外部查询先拿出一条数据,交给子查询,子查询按照条件进行过滤,如果满足条件,则count数字为符合条件的个数
查询结果
第一轮查询:先取出AUTOID为1的,UIFID为1,放入子查询中,查询m1.EPI_AUTOID >m2.EPI_AUTOID AND m1.EPI_UIFID = m2.EPI_UIFID,得出结果count(1)为0
第二轮查询:取出AUTOID为2的,UIFID为1,执行子查询,找到符合条件的数据,count(1)为1
依次进行查询,查询结果如下
| count(1) | EPI_AUTOID | EPI_UIFID | EPI_CNAME | EPI_DCREATEDT |
|---|---|---|---|---|
| 0 | 1 | 1 | 这是项目名1-1 | 2012-05-01 00:00:00 |
| 1 | 2 | 1 | 这是项目名1-2 | 2012-05-02 00:00:00 |
| 0 | 3 | 2 | 这是项目名2-1 | 2012-05-03 00:00:00 |
| 1 | 4 | 2 | 这是项目名2-2 | 2012-05-04 00:00:00 |
| 2 | 5 | 2 | 这是项目名2-3 | 2012-05-05 00:00:00 |
| 3 | 6 | 2 | 这是项目名2-4 | 2012-05-06 00:00:00 |
| 0 | 7 | 3 | 这是项目名3-1 | 2012-05-07 00:00:00 |
| 1 | 8 | 3 | 这是项目名3-2 | 2012-05-08 00:00:00 |
| 2 | 9 | 3 | 这是项目名3-3 | 2012-05-09 00:00:00 |
| 3 | 10 | 3 | 这是项目名3-4 | 2012-05-10 00:00:00 |
| 0 | 11 | 4 | 这是项目名4-1 | 2012-05-11 00:00:00 |
| 1 | 12 | 4 | 这是项目名4-2 | 2012-05-12 00:00:00 |
| 2 | 13 | 4 | 这是项目名4-3 | 2012-05-13 00:00:00 |
| 3 | 14 | 4 | 这是项目名4-4 | 2012-05-14 00:00:00 |
根据第3行的过滤条件,只过滤小于等于3的数据,所以产生如下结果
|count(1)|| EPI_AUTOID | EPI_UIFID | EPI_CNAME | EPI_DCREATEDT | | ---------- | ---------- | --------- | --------- | ------------- | |0| 1|1|这是项目名1-1|2012-05-01 00:00:00| |1| 2|1|这是项目名1-2|2012-05-02 00:00:00| |0| 3|2|这是项目名2-1|2012-05-03 00:00:00| |1| 4|2|这是项目名2-2|2012-05-04 00:00:00| |2| 5|2|这是项目名2-3|2012-05-05 00:00:00| |0| 7|3|这是项目名3-1|2012-05-07 00:00:00| |1| 8|3|这是项目名3-2|2012-05-08 00:00:00| |2| 9|3|这是项目名3-3|2012-05-09 00:00:00| |0| 11|4|这是项目名4-1|2012-05-11 00:00:00| |1| 12|4|这是项目名4-2|2012-05-12 00:00:00| |2| 13|4|这是项目名4-3|2012-05-13 00:00:00|
最后再进行排序,返回所需要的结果
这里可以通过控制第3行的大于号来控制需要保留的数据