在解析表达式中访问 "outer row" 值
Access "outer row" value in an analytic expression
我想访问我在其上编写分析表达式的“当前行”的值。例如,给定以下样本数据:
DROP TABLE emp PURGE;
CREATE TABLE emp (
empno NUMBER(4) CONSTRAINT pk_emp PRIMARY KEY,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
);
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,to_date('17-12-1980','dd-mm-yyyy'),800,NULL,20);
INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,to_date('20-2-1981','dd-mm-yyyy'),1600,300,30);
INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,to_date('22-2-1981','dd-mm-yyyy'),1250,500,30);
INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,to_date('2-4-1981','dd-mm-yyyy'),2975,NULL,20);
INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,to_date('28-9-1981','dd-mm-yyyy'),1250,1400,30);
INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,to_date('1-5-1981','dd-mm-yyyy'),2850,NULL,30);
INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10);
INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,to_date('13-7-87','dd-mm-rr')-85,3000,NULL,20);
INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10);
INSERT INTO emp VALUES (7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30);
INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,to_date('13-7-87', 'dd-mm-rr')-51,1100,NULL,20);
INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30);
INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,to_date('3-12-1981','dd-mm-yyyy'),3000,NULL,20);
INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,to_date('23-1-1982','dd-mm-yyyy'),1300,NULL,10);
COMMIT;
假设我想计算平均值(使用 deptno
进行分区)仅当薪水小于“外行”的薪水值时
这是计算特定 window 中每个人的平均值的查询,注释掉我希望能够执行的操作的行,“伪代码”。
SELECT t.empno, t.deptno, t.sal
,AVG(t.sal) OVER (PARTITION BY t.deptno) AS avg_dept_sal
--,AVG(CASE WHEN t.sal < OUTER_VALUE(t.sal) THEN t.sal ELSE NULL END) OVER (PARTITION BY t.deptno) AS avg_dept_sal_2
FROM emp t
;
因此,虽然 avg_dept_sal
returns ~2916 对于 deptno = 10
,对于每一行,avg_dept_sal_2
应该 return:
1300
对于 empno = 7782
1875
对于 empno = 7839
NULL
对于 empno = 7934
实现此目标的最佳方法是什么?
在解析函数中使用RANGE
window:
SELECT empno,
deptno,
sal,
AVG(sal) OVER (PARTITION BY deptno) AS avg_dept_sal,
AVG(sal) OVER (
PARTITION BY deptno
ORDER BY sal
RANGE BETWEEN UNBOUNDED PRECEDING AND 0.01 PRECEDING
) AS avg_dept_sal_2
FROM emp;
其中,对于示例数据,输出:
EMPNO
DEPTNO
SAL
AVG_DEPT_SAL
AVG_DEPT_SAL_2
7934
10
1300
2916.666666666666666666666666666666666667
null
7782
10
2450
2916.666666666666666666666666666666666667
1300
7839
10
5000
2916.666666666666666666666666666666666667
1875
7369
20
800
2175
null
7876
20
1100
2175
800
7566
20
2975
2175
950
7788
20
3000
2175
1625
7902
20
3000
2175
1625
7900
30
950
1566.666666666666666666666666666666666667
null
7654
30
1250
1566.666666666666666666666666666666666667
950
7521
30
1250
1566.666666666666666666666666666666666667
950
7844
30
1500
1566.666666666666666666666666666666666667
1150
7499
30
1600
1566.666666666666666666666666666666666667
1237.5
7698
30
2850
1566.666666666666666666666666666666666667
1310
db<>fiddle here
我想访问我在其上编写分析表达式的“当前行”的值。例如,给定以下样本数据:
DROP TABLE emp PURGE;
CREATE TABLE emp (
empno NUMBER(4) CONSTRAINT pk_emp PRIMARY KEY,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
);
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,to_date('17-12-1980','dd-mm-yyyy'),800,NULL,20);
INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,to_date('20-2-1981','dd-mm-yyyy'),1600,300,30);
INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,to_date('22-2-1981','dd-mm-yyyy'),1250,500,30);
INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,to_date('2-4-1981','dd-mm-yyyy'),2975,NULL,20);
INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,to_date('28-9-1981','dd-mm-yyyy'),1250,1400,30);
INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,to_date('1-5-1981','dd-mm-yyyy'),2850,NULL,30);
INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10);
INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,to_date('13-7-87','dd-mm-rr')-85,3000,NULL,20);
INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10);
INSERT INTO emp VALUES (7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30);
INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,to_date('13-7-87', 'dd-mm-rr')-51,1100,NULL,20);
INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30);
INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,to_date('3-12-1981','dd-mm-yyyy'),3000,NULL,20);
INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,to_date('23-1-1982','dd-mm-yyyy'),1300,NULL,10);
COMMIT;
假设我想计算平均值(使用 deptno
进行分区)仅当薪水小于“外行”的薪水值时
这是计算特定 window 中每个人的平均值的查询,注释掉我希望能够执行的操作的行,“伪代码”。
SELECT t.empno, t.deptno, t.sal
,AVG(t.sal) OVER (PARTITION BY t.deptno) AS avg_dept_sal
--,AVG(CASE WHEN t.sal < OUTER_VALUE(t.sal) THEN t.sal ELSE NULL END) OVER (PARTITION BY t.deptno) AS avg_dept_sal_2
FROM emp t
;
因此,虽然 avg_dept_sal
returns ~2916 对于 deptno = 10
,对于每一行,avg_dept_sal_2
应该 return:
1300
对于empno = 7782
1875
对于empno = 7839
NULL
对于empno = 7934
实现此目标的最佳方法是什么?
在解析函数中使用RANGE
window:
SELECT empno,
deptno,
sal,
AVG(sal) OVER (PARTITION BY deptno) AS avg_dept_sal,
AVG(sal) OVER (
PARTITION BY deptno
ORDER BY sal
RANGE BETWEEN UNBOUNDED PRECEDING AND 0.01 PRECEDING
) AS avg_dept_sal_2
FROM emp;
其中,对于示例数据,输出:
EMPNO DEPTNO SAL AVG_DEPT_SAL AVG_DEPT_SAL_2 7934 10 1300 2916.666666666666666666666666666666666667 null 7782 10 2450 2916.666666666666666666666666666666666667 1300 7839 10 5000 2916.666666666666666666666666666666666667 1875 7369 20 800 2175 null 7876 20 1100 2175 800 7566 20 2975 2175 950 7788 20 3000 2175 1625 7902 20 3000 2175 1625 7900 30 950 1566.666666666666666666666666666666666667 null 7654 30 1250 1566.666666666666666666666666666666666667 950 7521 30 1250 1566.666666666666666666666666666666666667 950 7844 30 1500 1566.666666666666666666666666666666666667 1150 7499 30 1600 1566.666666666666666666666666666666666667 1237.5 7698 30 2850 1566.666666666666666666666666666666666667 1310
db<>fiddle here