分类
MySql SQL 笔记

实现 MySQL Top 函数【原创】

需求:查询数据,根据字段分组,取出分组后每组的前N条记录。
如果是在SQL Server中,可以使用top,取前N条记录。但是在MySQL是不支持的。网上说的比较多的是用limit N,虽然可以取到前N条,但那是分组后的N条,不是每组N条数据,所以不符合需求,排除。还有一种是使用union把多个结果连接起来,这种方法需要提前知道有分多少组,而且不适合分组太多的场景,排除。

我的实现思路:
1.查出分组后的数据。
2.使用原表数据和分组后的数据连接起来。
3.按组生成序列(从0开始)。
4.根据序列编号做为条件,找出前N条数据。

SQL如下:
按月分组

SELECT
    tid, endDate
FROM
    reportform.reportform_user_active AS rua
GROUP BY DATE_FORMAT(endDate, '%y-%m');

执行结果:

给分组后的数据加上序列,rowNum(从0开始)。

SELECT
rua.tid,
rua.endDate,
(@i:=IF(tmp.tid IS NULL, @i + 1, @i:=0)) AS rowNum
FROM
reportform.reportform_user_active AS rua
LEFT JOIN (SELECT
tid, endDate
FROM
reportform.reportform_user_active
GROUP BY DATE_FORMAT(endDate, '%y-%m')) AS tmp ON tmp.tid = rua.tid, (SELECT @i:=0) AS i

执行结果:



可以看到,每月开始生成序号,从0开始。
最终SQL,取出前3条记录:

SELECT
    *
FROM
    (SELECT
        rua.tid,
            rua.endDate,
            (@i:=IF(tmp.tid IS NULL, @i + 1, @i:=0)) AS rowNum
    FROM
        reportform.reportform_user_active AS rua
    LEFT JOIN (SELECT
        tid, endDate
    FROM
        reportform.reportform_user_active
    GROUP BY DATE_FORMAT(endDate, '%y-%m')) AS tmp ON tmp.tid = rua.tid, (SELECT @i:=0) AS i) AS t
WHERE
    t.rowNum < 3;

执行结果:

提示:如果数据库是Oracle或SQL Server,可以用ROW_NUMBER函数生成序列。

发表评论

电子邮件地址不会被公开。