MySQL之伪列实现与实践

-------------------------------------------------------------------------------------------------正文--------------------------------------------------------------------------------------------------------------
问题来源:基情
问题描述:看图说明一切

建表语句与模板数据:

点击(此处)折叠或打开

  1. CREATE TABLE `tb_score` (
  2. `id` bigint(20) NOT NULL AUTO_INCREMENT ,
  3. `country` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
  4. `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
  5. `score` double NULL DEFAULT NULL ,
  6. PRIMARY KEY (`id`)
  7. )
  8. ENGINE=InnoDB
  9. DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci
  10. AUTO_INCREMENT=20
  11. ROW_FORMAT=COMPACT
  12. ;
  13. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (1, '中国', '张三', 81);
  14. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (2, '美国', 'Tom', 78);
  15. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (3, '英国', 'James', 67.5);
  16. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (4, '澳大利亚', 'Jack', 81);
  17. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (5, '澳大利亚', 'Roby', 64);
  18. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (6, '美国', 'Jory', 69);
  19. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (7, '中国', '李四', 92);
  20. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (8, '中国', '李天', 82);
  21. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (9, '中国', '王智', 71);
  22. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (10, '中国', '杨彦', 68.5);
  23. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (11, '澳大利亚', 'Jimmy', 92);
  24. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (12, '美国', 'Will', 81.5);
  25. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (13, '美国', 'Smirth', 79.5);
  26. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (14, '英国', 'Toki', 66);
  27. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (15, '澳大利亚', 'Kate', 89);
  28. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (16, '澳大利亚', 'Mercy', 88);
  29. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (17, '美国', 'Lance', 84.5);
  30. INSERT INTO `tb_score` (`id`, `country`, `name`, `score`) VALUES (18, '英国', 'Bandy', 77);

实践环境:MySQL-5.7.7-rc

实践过程:
首先看到这个需求,第一时间想到的就是Oracle的分组统计分析,当然了,MySQL没有,所以先生成了数据,直观的看一看效果:

总共四组,每一组都要选取成绩最好的前N(N=3)

直观的看,已有的ID,country,name,socre都无法作为where的条件去筛选出score最高的三个

那么跳出这些实际的数据,如果以上图这种顺序的数据结构为基础,要实现这个需求的话,

可以用这样子的抽象描述来表达实际需求的意思:以country的值为分组条件,每一组选第一行数据,第二行数据,...,第N行数据

那么在这种抽象描述里面,where的条件就可以做出来:每一组选第一行数据,第二行数据,...,第N行数据

so,可行方法就得出来了:以country的值为分组条件,构建伪列,最终结果筛选前N行数据,伪列值<=N(N=3)

问题来了,MySQL的伪列怎么构造?

构造位列的思想也是靠自连接来完成,使用count(*)来充当伪列的计数器,然后附加上计数的规则,
简单的构造示例:

点击(此处)折叠或打开

  1. select t1.*,
  2. (select count(*) from tb where id<=t1.id) as rownum
  3. from tb t1;

那么在这次的问题里面,这个伪列是有前提条件的:

1.以country的值为分组条件,那么显然,在构造伪列的where条件里面,我们必须限定这个伪列的count(*)所在的范围必须是在同一个country里面

添加clause1:连接条件为country

2.要选取分数最高的N(N=3)个,所以生成这个伪列的序列号的count(*)的计算方式,也是一个限制条件,

之前的clause1已经把范围限定在了同一个country,那么取分数最高,无非就是算一下比其他低的有多少,

比如以中国为例,想要最高分92的行作为伪列的第一行,代表着,92应该是<=(country=中国)的score的count

所以添加clause2:内表.score<=外表.score

分析完伪列构造的条件,那么就来看看实际构造的效果:

鼓掌撒花~按照每一个country为一组,根据score的大小成功构建了伪列

剩下,各位应该都知道怎么做了~加上 where rownum <=3即可~

最后贴上未经优化的强迫症SQL
点击(此处)折叠或打开

  1. select t3.id,t3.country,t3.score
  2. from (select t1.*, (select count(*) from tb_score t2 where t1.score<=t2.score and t1.country=t2.country) as rownum
  3. from tb_score t1) t3
  4. where rownum <=3 order by country,score DESC;

实际上MySQL对这个渣语句已经进行了优化:

目测是独立子查询往上提,果不其然:

------------------------------------------------------------------------------------------------全文完-----------------------------------------------------------------------------------------------------------

PS:伪列不错,灵活使用能够解决很多奇奇怪怪的需求~

时间: 2024-07-31 01:45:24

MySQL之伪列实现与实践的相关文章

Oracle Rownum伪列详解

oracle insert sql table jsp 咨询 Rowid 与 Rownum 虽都被称为伪列,但它们的存在方式是不一样的,rowid 可以说是物理存在的,表示记录在表空间中的唯一位置ID,在DB中唯一.只要记录没被搬动过,rowid是不变的.rowid 相对于表来说又像表中的一般列,所以以 rowid 为条件就不会有 rownum那些情况发生. rownum不能以任何基表的名称作为前缀. 对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1

MYSQL中设列的默认值为Now()

MySQL目前不支持列的Default为函数的形式,如达到你某列的默认值为当前更新日期与时间的功能,你可以使用TIMESTAMP列类型 下面就详细说明TIMESTAMP列类型 TIMESTAMP列类型 TIMESTAMP值可以从1970的某时的开始一直到2037年,精度为一秒,其值作为数字显示. TIMESTAMP值显示尺寸的格式如下表所示: : +---------------+----------------+ | 列类型 | 显示格式 | | TIMESTAMP(14) | YYYYMMD

mysql 数据库-关于mysql关联多列查询,分组查询并输出每组数据的中值

问题描述 关于mysql关联多列查询,分组查询并输出每组数据的中值 imei phone key value 863184021544828 lenovoa788t c14 484 355799050650579 samsungi9500 c14 542 355799050650579 samsungi9500 c14 623 868331013987821 huaweiu9508 c14 523 868331013987821 huaweiu9508 c14 498 8683310139878

oracle 中的伪列和表

1.oracle的伪列 oracle系统为了实现完整的关系数据库功能,系统专门提供了一组称为伪列(Pseudocolumn)的数据库列,这些列不是在建立对象时由我们完成的,而是在我们建立时由Oracle完成的.Oracle目前常见的伪列:  currval 和 nextval 使用序列号的保留字          CURRVAL:返回当前sequence值         NEXTVAL:增加sequence并返回下一个值  一般用法:   sequence.CURRVAL   sequence

浅析SQL Server数据库中的伪列以及伪列的含义

原文:浅析SQL Server数据库中的伪列以及伪列的含义   本文出处:http://www.cnblogs.com/wy123/p/6833116.html      SQL Server中的伪列 下午看QQ群有人在讨论(非聚集)索引的存储,说,对于聚集索引表,非聚集索引存储的是索引键值+聚集索引键值:对于非聚集索引表,索引存储的是索引键值+RowId,这应该是一个常识,对此不作具体详细阐述.这里主要是提到的RowId引起了一点思考.那么,这个RowId是个什么玩意?能不能更加直观一点来看看

mysql 数据库-mysql中表中列类型是枚举类型不能参与运算吗?

问题描述 mysql中表中列类型是枚举类型不能参与运算吗? 表结构: +------------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+---------------------+------+-----+---------+-------+ | sporter_id | char(4) | YES |

伪列应用 - 数据转存和下推

标签 PostgreSQL , FDW , 伪列 , function pushdown , DS , 时序数据 背景 金融.气象.物联网.互联网等行业,有特别多的时序数据,例如股票的交易数据,气象传感器的采集数据,车联网的轨迹数据,互联网的FEED数据,都具有非常强的时序属性. 时序数据如何有效的存储.方便的使用呢? 例如这样的写入 create table xx (xxx) ts interval day; insert into table values (x,x,x,x) ; 数据可以根

从关系型Mysql到Nosql HBase的迁移实践

2013年11月22-23日,作为国内唯一专注于Hadoop技术与应用分享的大规模行业盛会,2013 Hadoop中国技术峰会(China Hadoop Summit 2013)于北京福朋喜来登集团酒店隆重举行.来自国内外各http://www.aliyun.com/zixun/aggregation/17611.html">行业领域的近千名CIO.CTO.架构师.IT经理.咨询顾问.工程师.Hadoop技术爱好者,以及从事Hadoop研究与推广的IT厂商和技术专家将共襄盛举. 在SQL&

Mysql中 unique列插入重复值该怎么解决呢_Mysql

当unique列在一个UNIQUE键上插入包含重复值的记录时,我们可以控制MySQL如何处理这种情况:使用IGNORE关键字或者ON DUPLICATE KEY UPDATE子句跳过INSERT.中断操作或者更新旧记录为新值. mysql> create table menus(id tinyint(4) not null auto_increment, -> label varchar(10) null,url varchar(20) null,unique key(id)); Query