需要帮助了解 SQL 窗口函数之间的范围
Posted
技术标签:
【中文标题】需要帮助了解 SQL 窗口函数之间的范围【英文标题】:Need help understanding range between in SQL window functions 【发布时间】:2018-11-21 15:25:06 【问题描述】:我正在尝试了解 range 子句在以下情况下的工作原理(oracle 数据库)
SELECT
EMPID,NAME,
HIRE_DATE_1,
SALARY,
count(1) over(order by HIRE_DATE_1 range between 1 preceding and 1 preceding) as PREV_MIN_SA
FROM (
SELECT
EMPID,
NAME,
(EXTRACT(year from HIRE_DATE)*10000)+(EXTRACT(MONTH FROM HIRE_DATE) * 100) + (extract(DAY from HIRE_DATE)) as HIRE_DATE_1,SALARY
FROM EMPLOYEE A order by HIRE_DATE,SALARY
) A
ORDER BY HIRE_DATE_1
结果集:
EMPID NAME HIRE_DATE_1 SALARY PREV_MIN_SA
100 Ravi 20180101 5000 0
101 Kumar 20180101 7000 0
102 Satish 20180101 13000 0
103 Naresh 20180102 7500 3
105 Lalith 20180104 17300 0
104 Suresh 20180104 40000 0
106 Latha 20180201 16000 0
内部查询只是将日期转换为数字 YYYYMMDD 格式。 我的目的是计算每条记录中员工日期之前加入的人数。我可以计算具有相同 HIRE_DATE 的行数并使用 LAG 函数,但不知何故不明白 sql 如何返回此结果集。
此外,一旦我完成了计数,我想获得在当前行中的员工之前加入的员工的 MIN(SALARY),并找到薪水的差异,所以想知道我是否可以以某种方式定义窗口仅包含紧接在 HIRE_DATE 之前的所有记录。
谢谢
【问题讨论】:
您使用的是哪个 dbms? 请解释你要做什么。 计算HIRE_DATE_1
正好比当前行的HIRE_DATE_1
少一的行数。因为您努力将日期转换为整数,所以它将“打破”月份边界和年份边界。你为什么要把数据转换成整数!?
我使用的是 Oracle Live SQL(在线)所以不确定它在后台运行的是什么版本
@MatBailie :我在想“前面有 1 的范围”是指有序集中的值,而不是正好是 1 减。我转换为整数,因为我更喜欢整数算术而不是处理时间戳(oracle 似乎捕获日期数据类型中的时间戳)
【参考方案1】:
这应该得到之前的雇用日期...
SELECT
EMPID,NAME, HIRE_DATE, SALARY,
MAX(HIRE_DATE) OVER (ORDER BY HIRE_DATE
RANGE BETWEEN UNBOUNDED PRECEDING
AND INTERVAL '1 DAY' PRECEDING
)
AS PREV_HIRE_DATE
FROM
EMPLOYEE
那么我认为您需要重新加入员工表以查找员工人数和他们的最低工资?
SELECT
*
FROM
(
SELECT
EMPID,NAME, HIRE_DATE, SALARY,
MAX(HIRE_DATE) OVER (ORDER BY HIRE_DATE
RANGE BETWEEN UNBOUNDED PRECEDING
AND INTERVAL '1 DAY' PRECEDING
)
AS PREV_HIRE_DATE
FROM
EMPLOYEE
)
EMPS
LEFT JOIN
(
SELECT
HIRE_DATE,
COUNT(*) AS COUNT_EMPS,
MIN(SALARY) AS MIN_SALARY
FROM
EMPLOYEE
GROUP BY
HIRE_DATE
)
PREV_EMPS
ON PREV_EMPS.HIRE_DATE = EMPS.PREV_HIRE_DATE
编辑:
也许可以尝试这样的事情? (我必须跑,祝你好运!)
WITH
ranked AS
(
SELECT
*,
DENSE_RANK() OVER (ORDER BY HIRE_DATE) AS HIRE_SEQ_ID
FROM
EMPLOYEE
)
SELECT
*,
MIN(SALARY) OVER (ORDER BY HIRE_SEQ_ID
RANGE BETWEEN 1 PRECEDING AND 1 PRECEDING
)
AS PREV_MIN_SALARY,
COUNT(*) OVER (ORDER BY HIRE_SEQ_ID
RANGE BETWEEN 1 PRECEDING AND 1 PRECEDING
)
AS COUNT_PREV_EMPS
FROM
ranked
【讨论】:
@zulfi123786 运气好吗?【参考方案2】:我相信这就是你所追求的(我把它作为练习留给你找出最高和最低工资之间的差异!):
WITH employee AS (SELECT 100 empid, 'Ravi' NAME, to_date('01/01/2018', 'dd/mm/yyyy') hire_date, 5000 salary FROM dual UNION ALL
SELECT 101 empid, 'Kumar' NAME, to_date('01/01/2018', 'dd/mm/yyyy') hire_date, 7000 salary FROM dual UNION ALL
SELECT 102 empid, 'Satish' NAME, to_date('01/01/2018', 'dd/mm/yyyy') hire_date, 13000 salary FROM dual UNION ALL
SELECT 103 empid, 'Naresh' NAME, to_date('02/01/2018', 'dd/mm/yyyy') hire_date, 7500 salary FROM dual UNION ALL
SELECT 104 empid, 'Lalith' NAME, to_date('04/01/2018', 'dd/mm/yyyy') hire_date, 17300 salary FROM dual UNION ALL
SELECT 105 empid, 'Suresh' NAME, to_date('04/01/2018', 'dd/mm/yyyy') hire_date, 40000 salary FROM dual UNION ALL
SELECT 106 empid, 'Latha' NAME, to_date('01/02/2018', 'dd/mm/yyyy') hire_date, 16000 salary FROM dual)
SELECT empid,
NAME,
hire_date,
salary,
COUNT(*) OVER (ORDER BY hire_date RANGE BETWEEN 1 PRECEDING AND 1 PRECEDING) prev_day_hire_count,
MIN(salary) OVER (ORDER BY hire_date RANGE BETWEEN 1 PRECEDING AND 1 PRECEDING) prev_day_min_sal,
MAX(salary) OVER (ORDER BY hire_date RANGE BETWEEN 1 PRECEDING AND 1 PRECEDING) prev_day_max_sal
FROM employee;
EMPID NAME HIRE_DATE SALARY PREV_DAY_HIRE_COUNT PREV_DAY_MIN_SAL PREV_DAY_MAX_SAL
---------- ------ ----------- ---------- ------------------- ---------------- ----------------
100 Ravi 01/01/2018 5000 0
101 Kumar 01/01/2018 7000 0
102 Satish 01/01/2018 13000 0
103 Naresh 02/01/2018 7500 3 5000 13000
104 Lalith 04/01/2018 17300 0
105 Suresh 04/01/2018 40000 0
106 Latha 01/02/2018 16000 0
【讨论】:
EMPID 为 104 的行应该得到 PREV_DAY_MIN_SAL=7500。对于此记录,之前的日期是 '02/01/2018',并且只有一条记录,因此请考虑 7500。以上是关于需要帮助了解 SQL 窗口函数之间的范围的主要内容,如果未能解决你的问题,请参考以下文章