原文链接:http://hi.baidu.com/wangzhiqing999/item/7ca215d8ec9823ee785daa2b

MySQL 下 ROW_NUMBER / DENSE_RANK / RANK 的实现

CREATE TABLE test_rownum (
  ID  int,
  Ke CHAR(1),
  val INT
);

INSERT INTO test_rownum
  SELECT 1, 'A', 1 UNION ALL
  SELECT 2, 'A', 2 UNION ALL
  SELECT 3, 'A', 3 UNION ALL
  SELECT 4, 'B', 1 UNION ALL
  SELECT 5, 'B', 2 UNION ALL
  SELECT 6, 'B', 1 UNION ALL
  SELECT 7, 'C', 3 UNION ALL
  SELECT 8, 'C', 2 UNION ALL
  SELECT 9, 'C', 2;

rownum 用于显示序号
ID 字段用于 标记 原有的序号位置.

普通的处理
等价于 ROW_NUMBER() OVER (ORDER BY ke, val)

SELECT
  @rownum:=@rownum+1 AS rownum, 
  id,
  ke,
  val
FROM
  (SELECT @rownum:=0) r,
  test_rownum
ORDER BY
  ke, val;

+--------+------+------+------+
| rownum | id   | ke   | val  |
+--------+------+------+------+
|      1 |    1 | A    |    1 |
|      2 |    2 | A    |    2 |
|      3 |    3 | A    |    3 |
|      4 |    4 | B    |    1 |
|      5 |    6 | B    |    1 |
|      6 |    5 | B    |    2 |
|      7 |    8 | C    |    2 |
|      8 |    9 | C    |    2 |
|      9 |    7 | C    |    3 |
+--------+------+------+------+
9 rows in set (0.00 sec)

PARTITION 的处理
等价于 ROW_NUMBER() OVER (PARTITION BY ke ORDER BY val)

SELECT
  CASE 
    WHEN @ke != ke THEN @rownum:= 1 
    ELSE @rownum:= @rownum + 1  
    END AS rownum,
  id,
  @ke := ke AS ke,
  val
FROM
  (SELECT @ke:='') k,
  (SELECT @rownum:=0) r,
  test_rownum main
ORDER BY
  ke, val;
  
+--------+------+------+------+
| rownum | id   | ke   | val  |
+--------+------+------+------+
|      1 |    1 | A    |    1 |
|      2 |    2 | A    |    2 |
|      3 |    3 | A    |    3 |
|      1 |    4 | B    |    1 |
|      2 |    6 | B    |    1 |
|      3 |    5 | B    |    2 |
|      1 |    8 | C    |    2 |
|      2 |    9 | C    |    2 |
|      3 |    7 | C    |    3 |
+--------+------+------+------+
9 rows in set (0.00 sec)

RANK  DENSE_RANK 的处理
等价于 RANK() OVER (PARTITION BY ke ORDER BY val)

等价于 DENSE_RANK() OVER (PARTITION BY ke ORDER BY val)

SELECT
  CASE 
    WHEN @ke != ke THEN @rownum:= 1 
    ELSE @rownum:= @rownum + 1  
    END AS ROW_NUMBER,
  CASE 
    WHEN @ke != ke THEN @rank:= 1 
    WHEN @val = val THEN @rank
    ELSE @rank:= @rownum 
    END AS RANK,
  CASE 
    WHEN @ke != ke THEN @dense_rank:= 1 
    WHEN @val = val THEN @dense_rank
    ELSE @dense_rank:= @dense_rank + 1  
    END AS DENSE_RANK,
  id,
  @ke := ke AS ke,
  @val := val AS val
FROM
  (SELECT @ke:='') k,
  (SELECT @val:=0) v,
  (SELECT @rownum:=0) r,
  (SELECT @rank:=0) r2,
  (SELECT @dense_rank:=0) d,
  test_rownum main
ORDER BY
  ke, val;

+------------+------+------------+------+------+------+
| ROW_NUMBER | RANK | DENSE_RANK | id   | ke   | val  |
+------------+------+------------+------+------+------+
|          1 |    1 |          1 |    1 | A    |    1 |
|          2 |    2 |          2 |    2 | A    |    2 |
|          3 |    3 |          3 |    3 | A    |    3 |
|          1 |    1 |          1 |    4 | B    |    1 |
|          2 |    1 |          1 |    6 | B    |    1 |
|          3 |    3 |          2 |    5 | B    |    2 |
|          1 |    1 |          1 |    8 | C    |    2 |
|          2 |    1 |          1 |    9 | C    |    2 |
|          3 |    3 |          2 |    7 | C    |    3 |
+------------+------+------------+------+------+------+
9 rows in set (0.00 sec)

=======================================================
两表关联情况下的测试.

CREATE TABLE test_rownum_main (
  ID  int,
  Ke CHAR(1)
);

CREATE TABLE test_rownum_sub (
  KeID  int,
  val INT
);

INSERT INTO test_rownum_main
  SELECT 1, 'A'  UNION ALL
  SELECT 2, 'B'  UNION ALL
  SELECT 3, 'C';

INSERT INTO test_rownum_sub
  SELECT 1, 1 UNION ALL
  SELECT 1, 2 UNION ALL
  SELECT 1, 3 UNION ALL
  SELECT 2, 1 UNION ALL
  SELECT 2, 2 UNION ALL
  SELECT 2, 1 UNION ALL
  SELECT 3, 3 UNION ALL
  SELECT 3, 2 UNION ALL
  SELECT 3, 2;

普通的处理
等价于 ROW_NUMBER() OVER (ORDER BY ke, val)

SELECT
  @rownum:=@rownum+1 AS rownum, 
  main.id,
  main.ke,
  sub.val
FROM
  test_rownum_main main
    JOIN test_rownum_sub sub
      ON (main.ID = sub.KeID),
  (SELECT @rownum:=0) r
ORDER BY
  ke, val;

+--------+------+------+------+
| rownum | id   | ke   | val  |
+--------+------+------+------+
|      1 |    1 | A    |    1 |
|      2 |    1 | A    |    2 |
|      3 |    1 | A    |    3 |
|      4 |    2 | B    |    1 |
|      6 |    2 | B    |    1 |
|      5 |    2 | B    |    2 |
|      8 |    3 | C    |    2 |
|      9 |    3 | C    |    2 |
|      7 |    3 | C    |    3 |
+--------+------+------+------+
9 rows in set (0.00 sec)

rownum 顺序不满足预期结果了。
可能是因为执行关联的时候, 就把 @rownum 计算了。

修改SQL语句.

SELECT
  @rownum:=@rownum+1 AS rownum, 
  id,
  ke,
  val
FROM
  (SELECT @rownum:=0) r,
  (
  SELECT
    main.id,
    main.ke,
    sub.val
  FROM
    test_rownum_main main
      JOIN test_rownum_sub sub
        ON (main.ID = sub.KeID)
  ) subQuery
ORDER BY
  ke, val;

+--------+------+------+------+
| rownum | id   | ke   | val  |
+--------+------+------+------+
|      1 |    1 | A    |    1 |
|      2 |    1 | A    |    2 |
|      3 |    1 | A    |    3 |
|      4 |    2 | B    |    1 |
|      5 |    2 | B    |    1 |
|      6 |    2 | B    |    2 |
|      7 |    3 | C    |    2 |
|      8 |    3 | C    |    2 |
|      9 |    3 | C    |    3 |
+--------+------+------+------+
9 rows in set (0.00 sec)

PARTITION 的处理
等价于 ROW_NUMBER() OVER (PARTITION BY ke ORDER BY val)

SELECT
  CASE 
    WHEN @ke != ke THEN @rownum:= 1 
    ELSE @rownum:= @rownum + 1  
    END AS rownum,
  id,
  @ke := ke AS ke,
  val
FROM
  (SELECT @ke:='') k,
  (SELECT @rownum:=0) r,
  (
  SELECT
    main.id,
    main.ke,
    sub.val
  FROM
    test_rownum_main main
      JOIN test_rownum_sub sub
        ON (main.ID = sub.KeID)
  ) subQuery
ORDER BY
  ke, val;

+--------+------+------+------+
| rownum | id   | ke   | val  |
+--------+------+------+------+
|      1 |    1 | A    |    1 |
|      2 |    1 | A    |    2 |
|      3 |    1 | A    |    3 |
|      1 |    2 | B    |    1 |
|      2 |    2 | B    |    1 |
|      3 |    2 | B    |    2 |
|      1 |    3 | C    |    2 |
|      2 |    3 | C    |    2 |
|      3 |    3 | C    |    3 |
+--------+------+------+------+
9 rows in set (0.00 sec)

DENSE_RANK 的处理

RANK 的处理
等价于 DENSE_RANK() OVER (PARTITION BY ke ORDER BY val)

等价于 RANK() OVER (PARTITION BY ke ORDER BY val)

SELECT
  CASE 
    WHEN @ke != ke THEN @rownum:= 1 
    ELSE @rownum:= @rownum + 1  
    END AS ROW_NUMBER,
  CASE 
    WHEN @ke != ke THEN @rank:= 1 
    WHEN @val = val THEN @rank
    ELSE @rank:= @rownum 
    END AS RANK,
  CASE 
    WHEN @ke != ke THEN @dense_rank:= 1 
    WHEN @val = val THEN @dense_rank
    ELSE @dense_rank:= @dense_rank + 1  
    END AS DENSE_RANK,
  id,
  @ke := ke AS ke,
  @val := val AS val
FROM
  (SELECT @ke:='') k,
  (SELECT @val:=0) v,
  (SELECT @rownum:=0) r,
  (SELECT @rank:=0) r2,
  (SELECT @dense_rank:=0) d,
  (
  SELECT
    main.id,
    main.ke,
    sub.val
  FROM
    test_rownum_main main
      JOIN test_rownum_sub sub
        ON (main.ID = sub.KeID)
  ) subQuery
ORDER BY
  ke, val;

+------------+------+------------+------+------+------+
| ROW_NUMBER | RANK | DENSE_RANK | id   | ke   | val  |
+------------+------+------------+------+------+------+
|          1 |    1 |          1 |    1 | A    |    1 |
|          2 |    2 |          2 |    1 | A    |    2 |
|          3 |    3 |          3 |    1 | A    |    3 |
|          1 |    1 |          1 |    2 | B    |    1 |
|          2 |    1 |          1 |    2 | B    |    1 |
|          3 |    3 |          2 |    2 | B    |    2 |
|          1 |    1 |          1 |    3 | C    |    2 |
|          2 |    1 |          1 |    3 | C    |    2 |
|          3 |    3 |          2 |    3 | C    |    3 |
+------------+------+------------+------+------+------+
9 rows in set (0.00 sec)

MySQL 下 ROW_NUMBER / DENSE_RANK / RANK 的实现的更多相关文章

  1. SQL2005四个排名函数(row_number、rank、dense_rank和ntile)的比较

    排名函数是SQL Server2005新加的功能.在SQL Server2005中有如下四个排名函数: .row_number .rank .dense_rank .ntile 下面分别介绍一下这四个 ...

  2. ROW_NUMBER、RANK、DENSE_RANK的用法

    --NND,索性把2005的一起帖出来. ROW_NUMBER.RANK.DENSE_RANK的用法 (爱新觉罗.毓华 -- 广东深圳) SQL Server 引入几个新的排序(排名)函数,如ROW_ ...

  3. 四个排名函数(row_number、rank、dense_rank和ntile)的比较

    排名函数是SQL Server2005新加的功能.在SQL Server2005中有如下四个排名函数: 1.row_number 2.rank 3.dense_rank 4.ntile 下面分别介绍一 ...

  4. SQL中的排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)简介

    排名函数是Sql Server2005新增的功能,下面简单介绍一下他们各自的用法和区别. 在使用排名函数的时候需要注意以下三点: 1.排名函数必须有 OVER 子句. 2.排名函数必须有包含 ORDE ...

  5. Sql 四大排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)(转载)

    Sql 四大排名函数(ROW_NUMBER.RANK.DENSE_RANK.NTILE)简介   排名函数是Sql Server2005新增的功能,下面简单介绍一下他们各自的用法和区别.我们新建一张O ...

  6. hive笔记之row_number、rank、dense_rank

    hive中有三个与分组排序相关的分析函数(我起初也认为是窗口函数,后来看到手册里是把他们划到了Analytics functions下),row_number.rank.dense_rank,我一直傻 ...

  7. SQL With As 用法Sql 四大排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)简介

    Sql 四大排名函数(ROW_NUMBER.RANK.DENSE_RANK.NTILE)简介   排名函数是Sql Server2005新增的功能,下面简单介绍一下他们各自的用法和区别.我们新建一张O ...

  8. sql server 2000 对应 sql server 2005的row_number()、rank()、DENSE_RANK( )、ntile( )等用法

    转自CSDN:http://blog.csdn.net/htl258/article/details/4006717 SQL server 2005新增的几个函数,分别是row_number( ).r ...

  9. row_number()、rank()、dense_rank()、ntile()

    原文:row_number().rank().dense_rank().ntile() SQL2005中row_number()等函数的用法 2005比2000新增了几个函数,分别是row_numbe ...

随机推荐

  1. 一个人的安全部之ELK接收Paloalto日志并用钉钉告警

    起因 通报漏洞后,开发未能及时修复漏洞,导致被攻击,领导说我发现被攻击的时间晚了,由于一个人安全部精力有限未能及时看IPS告警,于是做了个钉钉告警. 本人环境介绍 ubuntu 14.04 pytho ...

  2. 批处理学习:for语句详解

    大纲 一 前言 二 for语句的基本用法 三 for /f (delims.tokens.skip.eol.userbackq.变量延迟) 四 for /r (递归遍历) 五 for /d (遍历目录 ...

  3. HDU4911:Inversion

    Problem Description bobo has a sequence a1,a2,-,an. He is allowed to swap two adjacent numbers for n ...

  4. Oracle基础 PL-SQL编程基础(2) 分支结构

    一.分支结构 1.if语句 语法: IF <布尔表达式> THEN PL/SQL和SQL语句 END IF; 示例: DECLARE v_count NUMBER := &n; B ...

  5. vue-router 导航守卫

    记住参数或查询的改变并不会触发进入/离开的导航守卫.你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫. 1.全局守卫 const router ...

  6. 懒人学习automake, Makefile.am,configure.ac(转)

    已经存在Makefile.am,如何生成Makefile? 步骤: [root@localhost hello]# autoscan .///在当前文件夹中搜索 [root@localhost hel ...

  7. 【Excle】在重复数据中对日期排序并查询最新的一条记录

    现在存在以下数据: 需要查询出以下数据 姓名       日期 张三       2017-12-14 李四       2017-12-16 在E1中写入以下公式:=IF(D2=MAX(IF($C$ ...

  8. 解决zabbix“ZBX_NOTSUPPORTED: Timeout while executing a shell script”报错

    如题所示,在zabbix_server使用zabbix_get获取自定义“UserParameter”对应的脚本的数据时,出现了如题所示的报错信息 [root@nmp01 scripts]# /usr ...

  9. Ansible@一个高效的配置管理工具--Ansible configure management--翻译(五)

    无书面许可请勿转载 高级Playbook Extra variables You may have seen in our template example in the previous chapt ...

  10. jar包解压与打包

    首先感谢大神的指导:https://blog.csdn.net/mr_pang/article/details/47028921 1.首先准备一个能运行的jar文件,我们使用第三方解压工具进行解压wi ...