| MySQL分析函数实现
还好MySQL8.0已经实现了与Oracle相同的分析函数。

1. 实现rownum
SET @rn:=0;
SELECT @rn:=@rn+1 AS rownum ,e.* FROM emp e;

或者写成:

SELECT @rn:=@rn + 1 AS rownum ,e.* FROM emp e ,(SELECT @rn:=0) c
2. 各种分析函数写法 (MySQL实现分析语句时可能遇到的各种计算问题)
2.1 sum() 实现

--SQL 执行顺序 ,FROM ,JOIN ,WHERE ,GROUP BY,HAVING ,ORDER BY ,SELECT,

在Oracle中分页语句的原始语句如下:

SELECT E.*, SUM(SAL) OVER(PARTITION BY DEPTNO) AS COUNTOVER FROM EMP E;

SELECT E.*,
(SELECT SUMOVER
FROM (SELECT DEPTNO, SUM(SAL) AS SUMOVER
FROM EMP E1
GROUP BY DEPTNO) X
WHERE X.DEPTNO = E.DEPTNO) AS COUNTOVER
FROM EMP E
ORDER BY DEPTNO;

Mysql中也是这么实现的:

SELECT E.*,
(SELECT SUMOVER
FROM (SELECT DEPTNO, SUM(SAL) AS SUMOVER
FROM emp E1
GROUP BY DEPTNO) X
WHERE X.DEPTNO = E.DEPTNO) AS COUNTOVER
FROM emp E
ORDER BY DEPTNO;

2.2 row_number () 实现

select
e.* ,row_number() over(partition by deptno order by empno) as ROW_NUMBER from emp e;

我们的默认规则是在from后初始化变量。

SELECT E.*,
IF(@DEPTNO = DEPTNO, @RN := @RN + 1, @RN := 1) AS ROW_NUMBER,
@DEPTNO := DEPTNO AS VAR1
FROM EMP E, (SELECT @DEPTNO := '', @RN := 0) C
ORDER BY DEPTNO;

SELECT E.*,
IF(@DEPTNO = DEPTNO, @RN := @RN + 1, @RN := 1) AS ROW_NUMBER,
@DEPTNO := DEPTNO AS VAR1
FROM EMP E, (SELECT @DEPTNO := '', @RN := 0) C
ORDER BY DEPTNO;
这个语句首先执行order by

2.3 求每个人员占他所在部门总工资的百分比

在Oracle中实现:

SELECT E.*,
TRUNC(SAL / SUM(SAL) OVER(PARTITION BY DEPTNO), 3) AS SALPERCENT
FROM EMP E
ORDER BY DEPTNO;

SELECT E.*,
SAL / (SELECT SUMOVER
FROM (SELECT DEPTNO, SUM(SAL) AS SUMOVER
FROM emp E1
GROUP BY DEPTNO) X
WHERE X.DEPTNO = E.DEPTNO) AS SalPercent
FROM emp E
ORDER BY DEPTNO;

2.4 求各个部门的总共工资

Oracle:

SELECT e.* ,SUM(sal) OVER(PARTITION BY deptno) FROM emp e;

MySQL:

SELECT A.*,
ROUND(CAST(IF(@DEPTNO = DEPTNO, @MAX := @MAX, @MAX := SUMOVER) AS CHAR ),0) AS SUMOVER2,
@DEPTNO := DEPTNO AS VAR2
FROM (SELECT E.*,
IF(@DEPTNO = DEPTNO, @SUM := @SUM + SAL, @SUM := SAL) AS SUMOVER,
@DEPTNO := DEPTNO AS VAR1
FROM emp E, (SELECT @DEPTNO := '', @SUM := 0, @MAX := 0) C
ORDER BY DEPTNO) A
ORDER BY DEPTNO, SUMOVER DESC;
子查询的功能实现如下:

下面是这个语句的结果

2.5 拿部门第二的工资的人

首先我们拿第二名的,用Oracle很好实现,不论是第一还是第二。

SELECT *
FROM (SELECT E.*,
ROW_NUMBER() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) AS RN
FROM EMP E)
WHERE RN = 2;

Mysql中第一这么实现:

在5.6版本,sql_mode非only_full_group_by的情况,我们可以使用如下方式实现

set global sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
SELECT * FROM (SELECT e.* FROM emp e ORDER BY deptno,sal ) a GROUP BY deptno;
在SQL_MODE非only_full_group_by时,MySQL中的group by是只取第一行的,下面我们看取第二行的SQL。

SELECT *
FROM (SELECT E.*,
IF(@DEPTNO = DEPTNO, @RN := @RN + 1, @RN := 1) AS RN,
@DEPTNO := DEPTNO
FROM EMP E, (SELECT @RN := 0, @DEPTNO := 0) C
ORDER BY DEPTNO, SAL DESC) X
WHERE X.RN = 2;

2.6 dense_rank()

dense_rank函数返回一个唯一的值,除非当碰到相同数据时,此时所有相同数据的排名都一样。

SELECT empno,
ename,
sal,
deptno,
rank() OVER(PARTITION BY deptno ORDER BY sal desc) as rank,
dense_rank() OVER(PARTITION BY deptno ORDER BY sal desc) as dense_rank
FROM emp e;

MySQL的写法:

select
empno,ename,sal,deptno,
if(@deptno = deptno,if(@sal=sal,@rn:=@rn,@rn3:=@rn3+1),@rn:=1) as "RANK() OVER",
if(@sal =sal,@rn2:=@rn2 ,if(@deptno = deptno,@rn2:=@rn2+1,@rn2:=1)) as "DENSE_RANK() OVER",
if(@deptno = deptno,@rn:=@rn+1,@rn:=1) as "ROW_NUMBER() OVER"
, @deptno:=deptno,@sal:=sal
from
(select empno,ename,sal,deptno from emp a ,(select @rn:=1,@deptno:=0,@rn2:=0,@rn3:=0,@sal:=0,@i:=0) b order by deptno,sal desc) c;

2.7 连续获得冠军的有哪些

--请写出一条SQL语句,查询出在此期间连续获得冠军的有哪些,其连续的年份的起止时间是多少,结果如下:

create table nba as
SELECT '公牛' AS TEAM, '1991' AS Y FROM DUAL UNION ALL
SELECT '公牛' AS TEAM, '1992' AS Y FROM DUAL UNION ALL
SELECT '公牛' AS TEAM, '1993' AS Y FROM DUAL UNION ALL
SELECT '活塞' AS TEAM, '1990' AS Y FROM DUAL UNION ALL
SELECT '火箭' AS TEAM, '1994' AS Y FROM DUAL UNION ALL
SELECT '火箭' AS TEAM, '1995' AS Y FROM DUAL UNION ALL
SELECT '公牛' AS TEAM, '1996' AS Y FROM DUAL UNION ALL
SELECT '公牛' AS TEAM, '1997' AS Y FROM DUAL UNION ALL
SELECT '公牛' AS TEAM, '1998' AS Y FROM DUAL UNION ALL
SELECT '马刺' AS TEAM, '1999' AS Y FROM DUAL UNION ALL
SELECT '湖人' AS TEAM, '2000' AS Y FROM DUAL UNION ALL
SELECT '湖人' AS TEAM, '2001' AS Y FROM DUAL UNION ALL
SELECT '湖人' AS TEAM, '2002' AS Y FROM DUAL UNION ALL
SELECT '马刺' AS TEAM, '2003' AS Y FROM DUAL UNION ALL
SELECT '活塞' AS TEAM, '2004' AS Y FROM DUAL UNION ALL
SELECT '马刺' AS TEAM, '2005' AS Y FROM DUAL UNION ALL
SELECT '热火' AS TEAM, '2006' AS Y FROM DUAL UNION ALL
SELECT '马刺' AS TEAM, '2007' AS Y FROM DUAL UNION ALL
SELECT '凯尔特人' AS TEAM, '2008' AS Y FROM DUAL UNION ALL
SELECT '湖人' AS TEAM, '2009' AS Y FROM DUAL UNION ALL
SELECT '湖人' AS TEAM, '2010' AS Y FROM DUAL;
Oracle实现:

SELECT TEAM, MIN(Y), MAX(Y)
FROM (SELECT E.*,
ROWNUM,
ROW_NUMBER() OVER(PARTITION BY TEAM ORDER BY Y) AS RN,
ROWNUM - ROW_NUMBER() OVER(PARTITION BY TEAM ORDER BY Y) AS DIFF
FROM NBA E
ORDER BY Y)
GROUP BY TEAM, DIFF
HAVING MIN(Y) != MAX(Y)
ORDER BY 2;
MySQL实现:

SELECT TEAM, MIN(Y), MAX(Y)
FROM (SELECT TEAM,
Y,
IF(@TEAM = TEAM, @RN := @RN + 1, @RN := 1) AS RWN,
@RN1 := @RN1 + 1 AS RN,
@TEAM := TEAM
FROM nba N, (SELECT @RN := 0, @TEAM := '', @RN1 := '') C) A
GROUP BY RN - RWN
HAVING MIN(Y) != MAX(Y)
ORDER BY 2

| UDF插件
Userdefined Function,用户定义函数。我们知道,MySQL本身支持很多内建的函数,此外还可以通过创建存储方法来定义函数。UDF为用户提供了一种更高效的方式来创建函数。

UDF与普通函数类似,有参数,也有输出。分为两种类型:单次调用型和聚集函数。前者能够针对每一行数据进行处理,后者则用于处理Group By这样的情况。

UDF自定义函数,在MySQL basedir/include

[root@test12c include]# pwd
/usr/local/mysql/include
[root@test12c include]# cat rownum.c
#include <my_global.h>
#include <my_sys.h>

#if defined(MYSQL_SERVER)
#include <m_string.h> /* To get strmov() */
#else
/* when compiled as standalone */
#include <string.h>
#define strmov(a,b) stpcpy(a,b)
#endif

#include <mysql.h>
#include <ctype.h>

/*
gcc -fPIC -Wall -I/usr/local/mysql/include -I. -shared rownum.c -o rownum.so
DROP FUNCTION IF EXISTS rownum;
CREATE FUNCTION rownum RETURNS INTEGER SONAME 'rownum.so';
*/

C_MODE_START;

my_bool rownum_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
void rownum_deinit(UDF_INIT *initid);
chong rownum(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error);

C_MODE_END;

/*
Simple example of how to get a sequences starting from the first argument
or 1 if no arguments have been given
*/

my_bool rownum_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count > 1)
{
strmov(message,"This function takes none or 1 argument");
return 1;
}
if (args->arg_count)
args->arg_type[0]= INT_RESULT; /* Force argument to int */

if (!(initid->ptr=(char*) malloc(sizeof(chong))))
{
strmov(message,"Couldn't allocate memory");
return 1;
}
memset(initid->ptr, 0, sizeof(chong));
initid->const_item=0;
return 0;
}

void rownum_deinit(UDF_INIT *initid)
{
if (initid->ptr)
free(initid->ptr);
}

chong rownum(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,char *is_null __attribute__((unused)),char *error __attribute__((unused)))
{
uchong val=0;
if (args->arg_count)
val= *((chong*) args->args[0]);
return ++*((chong*) initid->ptr) + val;
}
生成动态链接库

gcc rownum.c -fPIC -shared -o ../lib/plugin/rownum.so

|  作者简介
姚崇·沃趣科技高级数据库技术专家

熟悉Oracle、MySQL数据库内部机制,丰富的Oracle、MySQL故障诊断、性能调优、数据库备份恢复、复制、高可用方案及迁移经验。
---------------------
作者:woqutechteam
来源:CSDN
原文:https://blog.csdn.net/woqutechteam/article/details/83501038
版权声明:本文为博主原创文章,转载请附上博文链接!

MySQL分析函数实现的更多相关文章

  1. 有关mysql实现oracle分析函数功能的方法

    目前公司erp开发有一个脚本需求:对于收款合同审批单和收款合同(n:1),需要获取收款审批单中最新的一条审批记录来更新其对应的收款合同的相关信息. 难点主要在对相同类别的属性进行分组然后组内排序(分组 ...

  2. mysql实现开窗函数、Mysql实现分析函数

    关键字:mysql实现开窗函数.Mysql实现分析函数.利用变量实现窗口函数 注意,变量是从左到右顺序执行的 --测试数据 CREATE TABLE `tem` ( `id` ) NOT NULL A ...

  3. MySQL中的GIS几何函数和空间分析函数

    MySQL空间扩展不仅提供了空间数据的存储能力,而且还具备一些空间运算能力,这些功能通过MySQL内建的几何函数实现.最简单的几何函数昨天已经有所涉及,也就是转换WTK的GEOMFROMTEXT和AS ...

  4. PostgreSQL 与 MySQL 相比,优势何在?

    一. PostgreSQL 的稳定性极强, Innodb 等引擎在崩溃.断电之类的灾难场景下抗打击能力有了长足进步,然而很多 MySQL 用户都遇到过Server级的数据库丢失的场景——mysql系统 ...

  5. mysql、sql server、oracle数据库分页查询及分析(操作手册)

    1.mysql分页查询 方式1: select * from table order by id limit m, n; 该语句的意思为,查询m+n条记录,去掉前m条,返回后n条记录.无疑该查询能够实 ...

  6. 从Oracle迁移到Mysql之前必须知道的50件事

    1. 对子查询的优化表现不佳. 2. 对复杂查询的处理较弱 3. 查询优化器不够成熟 4. 性能优化工具与度量信息不足 5. 审计功能相对较弱 6. 安全功能不成熟,甚至可以说很粗糙.没有用户组与角色 ...

  7. mysql和oracle的mybatis操作

    1.Oracle.MySQL插入时返回下一个主键的操作 Oracle:<insert id="insert" parameterClass="ROLE"& ...

  8. MySQL、SqlServer、Oracle三大主流数据库分页查询

    在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法.可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应用 ...

  9. MariaDB10.2.X-新特性1-支持分析函数

    前言:前段时间看到MariaDB10.2出测试版本了,心想有什么新特性玩玩,大家都知道MySQL不支持分析函数,但是MariaDB10.2.X支持分析函数了, 1.表结构 CREATE TABLE ` ...

随机推荐

  1. Hadoop2源码分析-Hadoop V2初识

    1.概述 在完成分析Hadoop2源码的准备工作后,我们进入到后续的源码学习阶段.本篇博客给大家分享,让大家对Hadoop V2有个初步认识,博客的目录内容如下所示: Hadoop的渊源 Hadoop ...

  2. How to correctly handle ThreadLocal.get() returning null

    Java's ThreadLocals make certain things easy, but special care must be taken to make sure they are r ...

  3. Deep learning with Python 学习笔记(4)

    本节讲卷积神经网络的可视化 三种方法 可视化卷积神经网络的中间输出(中间激活) 有助于理解卷积神经网络连续的层如何对输入进行变换,也有助于初步了解卷积神经网络每个过滤器的含义 可视化卷积神经网络的过滤 ...

  4. webpack4 自学笔记五(tree-shaking)

    全部的代码及笔记都可以在我的github上查看, 欢迎star: https://github.com/Jasonwang911/webpackStudyInit/tree/master/ThreeS ...

  5. 浅析 JavaScript 链式调用

    对$函数你已经很熟悉了.它通常返回一个html元素或一个html元素的集合,如下: function$(){ var elements = []; for(vari=0,len=arguments.l ...

  6. laravel 文件上传

    laravel 文件上传 先开扩展 表单中能够选择图片 数据处理C层, 接图片并保存 保存图片: 设置目录 store()的第一个参数说明: 存放图片的子目录. 如何获取文件的类型 大小: $uplo ...

  7. XML Parsing Error: no element found Location: moz-nullprincipal:{23686e7a-652b-4348-92f4-7fb3575179ed} Line Number 1, Column 1:^

    “Hi Insus.NET, 我有参考你下午发布的一篇<jQuery.Ajax()执行WCF Service的方法>http://www.cnblogs.com/insus/p/37278 ...

  8. ADO.NET 【增】【删】【改】【查】

    数据访问  Using System.Data.SqlClient;   对应命名空间                                       -- SqlConnection   ...

  9. [日常] Go语言圣经-Deferred函数

    1.只需要在调用普通函数或方法前加上关键字defer,就完成了defer所需要的语法.当defer语句被执行时,跟在defer后面的函数会被延迟执行.直到包含该defer语句的函数执行完毕时,defe ...

  10. oracle安装与备份导入

    win10安装oracle因运行版本问题导致安装时提示错误(可能win10未被甲骨文公司认证)  跳过的问题 需要更改配置文件: 配置位置在 : 具体操作如下图: 在安装时win10跳过了 许是因为环 ...