用mysql實現oracle的分析函式
最近資料中心環境切換,源資料儲存在oracle11g裡,新環境要mysql5.7, 由於很多的sql語句用到了oracle的分析函式,而mysql對此暫無很好的支援,所以做了以下的轉化,作為標記,有錯誤的地方,希望大家指正。
一。準備工作
1.資料表準備
oracle的scott使用者下,有emp表,我這裡基於它進行驗證
(1)mysql建表語句
CREATE TABLE `emp` (
`empno` DECIMAL(4,0) NOT NULL,
`ename` VARCHAR(10) NULL DEFAULT NULL,
`job` VARCHAR(9) NULL DEFAULT NULL,
`mgr` DECIMAL(4,0) NULL DEFAULT NULL,
`hiredate` DATE NULL DEFAULT NULL,
`sal` DECIMAL(7,2) NULL DEFAULT NULL,
`comm` DECIMAL(7,2) NULL DEFAULT NULL,
`deptno` DECIMAL(2,0) NULL DEFAULT NULL
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
(2)資料準備
INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800.00, 0.00, 20);
INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600.00, 300.00, 30);
INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250.00, 500.00, 30);
INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975.00, 0.00, 20);
INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30);
INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850.00, 0.00, 30);
INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450.00, 0.00, 10);
INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3000.00, 0.00, 20);
INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', 0, '1981-11-17', 5000.00, 0.00, 10);
INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500.00, 0.00, 30);
INSERT INTO `emp` VALUES (7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1100.00, 0.00, 20);
INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950.00, 0.00, 30);
INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000.00, 0.00, 20);
INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300.00, 0.00, 10);
---------------------------------------------------------------------
1.oracle row_number over-》mysql自定義變數(1)oracle
select deptno,sal,row_number() over(partition by deptno order by sal) rownumber from scott.emp
select
tmp.deptno,
tmp.sal,
IF (@deptno = tmp.deptno,@rownumber:[email protected]
@deptno := tmp.deptno as dtno
FROM
(
SELECT deptno,sal FROM emp
ORDER BY deptno,sal
) tmp,
(SELECT @deptno := NULL,@rownumber:= 0) a
2.oracle first_value ->mysql自定義變數
(1)oracle
SELECT DEPTNO,
JOB,
SAL,
FIRST_VALUE(SAL) OVER(PARTITION BY DEPTNO ORDER BY DEPTNO) firstvalue
FROM scott.EMP
select a.DEPTNO,a.JOB,a.SAL,m.sal
from emp a left outer join
(
SELECT DEPTNO,JOB,SAL
from
(
SELECT DEPTNO,
JOB,
SAL,
@num := if(@DEPTNO = DEPTNO, @num + 1, 1) as row_number,
@DEPTNO := DEPTNO as dummy
FROM emp
order by DEPTNO,SAL
) x
where x.row_number=1
order by DEPTNO,SAL
) m
on a.deptno = m.deptno
3.ratio_to_report的oracle-》mysql
(1)oracle
SELECT
empno,ename,sal,deptno,
ratio_to_report(sal) over () as pct1l,
ratio_to_report(sal) over (partition by deptno) as pct2
FROM scott.emp;
select a.DEPTNO,a.JOB,a.SAL,a.sal/m.s
from emp a left outer join
(
select sal,deptno,sum(sal) as s
from emp
group by DEPTNO
) m
on a.deptno = m.deptno
order by a.DEPTNO
4.max,min,avg,count over -> mysql
(1)oracle
SELECT deptno,
max(sal) over (partition by deptno) as maxsal,
min(sal) over (partition by deptno) as minsal,
avg(sal) over (partition by deptno) as avgsal,
count(sal) over (partition by deptno) as maxsal
FROM scott.emp;
(2)mysql
SELECT a.deptno,m.maxsal,m.minsal,m.avgsal,m.countsal
FROM emp a
LEFT OUTER
JOIN (
SELECT deptno,MAX(sal) maxsal,MIN(sal) minsal,AVG(sal) avgsal,COUNT(sal) countsal
FROM emp
GROUP BY deptno
) m ON a.deptno = m.deptno
order by a.deptno
5.用row_number實現oracle的lag函式
(1)oracle
select deptno,sal,lag(sal,1) over(partition by deptno order by sal) from scott.emp
(2)mysql
select main.deptno,main.rownumber,main.sal,ano.sal as lagsal,ano.rownumber
from
(
select
tmp.deptno,
tmp.sal,
IF (@deptno = tmp.deptno,@rownumber:[email protected]+ 1,@rownumber:= 1) AS rownumber,
@deptno := tmp.deptno as dtno
FROM
(
SELECT deptno,sal FROM emp
ORDER BY deptno,sal
) tmp,
(SELECT @deptno := NULL,@rownumber:= 0) a
) main left join
(
select
tmp.deptno,
tmp.sal,
IF (@deptno = tmp.deptno,@rownumber:[email protected]+ 1,@rownumber:= 1) AS rownumber,
@deptno := tmp.deptno as dtno
FROM
(
SELECT deptno,sal FROM emp
ORDER BY deptno,sal
) tmp,
(SELECT @deptno := NULL,@rownumber:= 0) a
) ano
on main.deptno=ano.deptno and ano.rownumber=main.rownumber-1