Mysql 特殊操作场景

76 阅读4分钟

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_AUTOIDEPI_UIFIDEPI_CNAMEEPI_DCREATEDT
11这是项目名1-12012-05-01
21这是项目名1-22012-05-02
32这是项目名2-12012-05-03
42这是项目名2-22012-05-04
52这是项目名2-32012-05-05
62这是项目名2-42012-05-06
73这是项目名3-12012-05-07
83这是项目名3-22012-05-08
93这是项目名3-32012-05-09
103这是项目名3-42012-05-10
114这是项目名4-12012-05-11
124这是项目名4-22012-05-12
134这是项目名4-32012-05-13
144这是项目名4-42012-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_AUTOIDEPI_UIFIDEPI_CNAMEEPI_DCREATEDT
011这是项目名1-12012-05-01 00:00:00
121这是项目名1-22012-05-02 00:00:00
032这是项目名2-12012-05-03 00:00:00
142这是项目名2-22012-05-04 00:00:00
252这是项目名2-32012-05-05 00:00:00
362这是项目名2-42012-05-06 00:00:00
073这是项目名3-12012-05-07 00:00:00
183这是项目名3-22012-05-08 00:00:00
293这是项目名3-32012-05-09 00:00:00
3103这是项目名3-42012-05-10 00:00:00
0114这是项目名4-12012-05-11 00:00:00
1124这是项目名4-22012-05-12 00:00:00
2134这是项目名4-32012-05-13 00:00:00
3144这是项目名4-42012-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行的大于号来控制需要保留的数据