oracle的case-when,row_number(),trunc()函数

本文详细介绍了Oracle SQL中的三个重要函数:case-when用于按指定条件分组显示内容;row_number()用于对查询结果进行排序;trunc()用于对数字和日期进行截断处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  今天我们来讲一讲oracle的SQL语句中几个比较重要很深入的函数。

 1. 第一个是case-when函数

  他的作用是将数据库表格中的某一列上的值进行分组显示,显示我们想要强制性显示的内容。举例:

  select (case id when 10 then '第一个' when 14 then '第二个' else '第三个' end ) 顺序 from ssh_employee

  显示效果见附件。

  2.第二个函数是row_number()

  这个函数的作用是将查询结果按照某列分组之后再在组内进行排序。

  举例:

 select row_number() over(partition by column1 order by column2) sum from ssh_employee

  表示按照column1分组,然后在组内再按照column2进行排序。

  注意,row_number()是非确定性的(如返回值为12,13,14,15.但结果又可能是12,14,13,15),而rank()和dense_rank()是确定性函数

  显示结果见附件。

  此外,oracle也可以用rownum这个伪列来获取前几名,也很有效,但是需要使用select语句将这个伪列显式出来才可以使用>=,否则只可以用<=。

  rownum()这个伪列和order by结合时,也会产生一个很有意思的现象。

  在使用rownum时,只有当order by的字段是主键时,才会产生我们想要的先按照主键排序再计算rownum的情况。

  3.第三个是trunc()函数

  truncate表示截取,截断的意思。它可以操作的对象是日期类型和数字类型。

  ① 当操作数字类型时,需要传入两个参数,第一个是要截取的数字类型的对象,第二个是相对于小数点来说要截取到的位置,默认为0。注意,trunc()函数截取时是不会进行四舍五入的。例子:trunc(123.567,0)得到的结果是,123。trunc(123.567,-1) 得到的结果是120。

  ② 当操作日期类型时,也需要传入两个参数.第一个表示要操作的日期类型的对象。第二个表示要截取的内容。具体可以返回当前年,月的第一天。或者返回当前时间,精确到天,时 ,分,但是不会精确到秒。

 

如下SQL,D.POINT_TIME - TRUNC(D.POINT_TIME)再去掉1秒:WITH work_s AS ( SELECT A.EMP_CODE, A.EMPNAME, A.WORK_DATE, B.WS_NUMBER, B.WS_SIMPLE_NAME, C.LAST_TIME_TOTAL, D.POINT_TIME, D.ADV_TIME, D.OVER_TIME, D.WP_TYPE, D.IS_NEXT_DAY, -- 修复时间计算 CASE WHEN D.WP_TYPE = 2 AND D.IS_NEXT_DAY = 1 THEN TRUNC(A.WORK_DATE) + 1 + (D.POINT_TIME - TRUNC(D.POINT_TIME)) ELSE TRUNC(A.WORK_DATE) + (D.POINT_TIME - TRUNC(D.POINT_TIME)) END AS base_time, TRUNC(A.WORK_DATE) + (D.POINT_TIME - TRUNC(D.POINT_TIME)) + CASE WHEN D.WP_TYPE = 2 THEN (C.LAST_TIME_TOTAL + CASE WHEN B.WS_NUMBER IN ('035A','035B') THEN 90 WHEN B.WS_NUMBER = '005A' THEN 60 ELSE 120 END)/1440 ELSE 0 END + CASE WHEN D.IS_NEXT_DAY = 1 THEN 1 ELSE 0 END AS overpoint_time, CASE WHEN B.WS_NUMBER = '005A' AND D.WP_TYPE = 2 THEN TRUNC(A.WORK_DATE) + (D.POINT_TIME - TRUNC(D.POINT_TIME)) + (C.LAST_TIME_TOTAL + 240)/1440 END AS overpoint_time2 FROM HCP.v_clk_tz_emp_workday_info A JOIN HCP.v_clk_work_shift B ON A.WS_ID = B.ID JOIN HCP.v_clk_work_block C ON A.WS_ID = C.WS_ID JOIN HCP.v_clk_work_point D ON C.ID = D.WB_ID WHERE A.WORK_DATE = TRUNC(SYSDATE-1) ), attendance_data AS ( SELECT DECODE(HPB.WORK_PLACE, 0, 'LSP1', 1, 'LSP2', 2, 'LSP3') AS MASTER_NO, DECODE(HPB.WORK_PLACE, 0, '一园', 1, '二园', 2, '三园') AS WORK_PLACE, HPB.EMPCODE, HPB.EMPNAME, FF.FGT02, FF.FGT08, SUBSTR(FF.FGT08,3,1) AS card_type, HPB.RANK_NAME, HPB.ORG_NAME, DECODE(H.SALARY_TYPE,1,'月薪',2,'计时',3,'计件') AS SALARY_TYPE FROM FINGER5.FGT_FILE FF JOIN HCP.TZ_EMP_IN HPB ON FF.FGT10 = HPB.EMPCODE JOIN HCP.v_clk_tz_employee H ON FF.FGT10 = H.EMPCODE JOIN work_s A ON A.EMP_CODE = FF.FGT10 WHERE FF.FGT02 >= TRUNC(SYSDATE-1) AND FF.FGT02 < TRUNC(SYSDATE) -- 优化为闭开区间 AND FF.FGT03 <> '4' AND LENGTH(FF.FGT08) = 5 AND SUBSTR(FF.FGT08,3,1) IN ('1','2') AND ( (SUBSTR(FF.FGT08,3,1) = '1' AND A.WP_TYPE = 1 AND FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE) OR (SUBSTR(FF.FGT08,3,1) = '2' AND A.WP_TYPE = 2 AND ( CASE WHEN H.SALARY_TYPE = 1 THEN CASE WHEN FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE THEN 1 ELSE 0 END WHEN A.WS_NUMBER = '005A' THEN CASE WHEN FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE OR FF.FGT02 BETWEEN A.overpoint_time AND A.overpoint_time + INTERVAL '1' MINUTE OR FF.FGT02 BETWEEN A.overpoint_time2 AND A.overpoint_time2 + INTERVAL '1' MINUTE THEN 1 ELSE 0 END ELSE CASE WHEN FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE OR FF.FGT02 BETWEEN A.overpoint_time AND A.overpoint_time + INTERVAL '1' MINUTE THEN 1 ELSE 0 END END = 1 )) ) ), attendance_filtered AS ( SELECT MASTER_NO, WORK_PLACE, EMPCODE, EMPNAME, FGT02, FGT08, card_type, DECODE(card_type, '1', '上班卡', '2', '下班卡') AS status, RANK_NAME, ORG_NAME, SALARY_TYPE, ROW_NUMBER() OVER ( PARTITION BY EMPCODE, card_type ORDER BY FGT02 ASC ) AS rank -- 按员工和打卡类型分区,取最早记录 FROM attendance_data ), tz_opr AS ( SELECT KLV.MEANING, KLV.DESCRIPTION, KLV.REVERSE2, KLV.REVERSE1, KLV.REVERSE3 IP, KLV.REVERSE4 FROM HCP.KS_LOOKUP_VALUE KLV WHERE KLV.LOOKUP_TYPE = 'KQ_SEPARATE_MACHINE' AND KLV.ENABLED = 'Y' ) SELECT MASTER_NO, WORK_PLACE AS MASTER_NAME, EMPCODE AS ID_NO_SZ, EMPNAME AS NAME_SZ, FGT02 AS RECORDTIME, FGT08 AS MACHINE_NO, trunc(SYSDATE-1) AS CDAY, -- 修改为TRUNC确保纯日期输出 A.REVERSE4 AS MACHINE_LOC, status AS SHIFTTYPE, RANK_NAME AS TITLE_NO, HCP.SF_LSHR_NO_GET(EMPCODE, 18) AS TITLE_NAME, SALARY_TYPE, HCP.SF_LSHR_NO_GET(EMPCODE, 2) AS SEGMENT_NO, HCP.SF_LSHR_NO_GET(EMPCODE, 13) AS SEGMENT_NAME, SUBSTR(HCP.SF_LSHR_NO_GET(EMPCODE, 15), LENGTH(HCP.SF_LSHR_NO_GET(EMPCODE, 15))-5) AS DEPT_NO, -- 取后6位 HCP.SF_LSHR_NO_GET(EMPCODE, 15) AS DEPT_NAME, HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(EMPCODE, 9), 8) AS TOEMAIL, HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(EMPCODE, 10), 8) || ';' || HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(EMPCODE, 11), 8) AS CCEMAIL, '' AS TEMP_COMPANY FROM attendance_filtered JOIN tz_opr A ON FGT08 = A.MEANING WHERE rank = 1 -- 取每个员工每个打卡类型的最早记录 ORDER BY status, FGT02; -- 按打卡类型和时间排序
最新发布
08-02
如下SQL需查找并统计年假未休请协助修改, 并优化oracle如下SQL性能,提高执行效率和减少资源占用: WITH V_DATA AS( SELECT HCP.SF_LSHR_NO_GET(A.EMP_CODE,19) WORK_PLACE, A.EMP_CODE,A.EMP_NAME,A.ANNUAL_LEAVE,A.YEAR FROM HCP.v_clk_tz_annual_leave A WHERE annual_leave>0 AND YEAR = 2025 --AND EMP_CODE='TZ143941' --AND ((TO_CHAR(SYSDATE, 'mm') IN ('04', '05', '06', '07', '08', '09') AND -- TRUNC(SYSDATE) IN -- (SELECT MAX(B.A) -- FROM (SELECT TRUNC(SYSDATE, 'mm') + ROWNUM - 1 A -- FROM DBA_OBJECTS -- WHERE ROWNUM < 32) B -- WHERE TO_CHAR(B.A, 'day') = 'friday ')) OR -- (TO_CHAR(SYSDATE, 'mm') IN ('10', '11') AND -- TO_CHAR(SYSDATE, 'Day') = 'Friday ') OR -- TO_CHAR(SYSDATE, 'mm') = '12') ), DEPT_PEOPLE AS( SELECT EMP_CODE,MEANING,HCP.SF_LSHR_NO_GET(MEANING, 8) V_EMAIL FROM ( SELECT T.EMP_CODE,MEANING,ROWNUM FROM V_DATA T JOIN HCP.KS_LOOKUP_VALUE KLV ON (KLV.REVERSE2 = SUBSTR(HCP.SF_LSHR_NO_GET(T.EMP_CODE, 15), LENGTH(HCP.SF_LSHR_NO_GET(T.EMP_CODE, 15))-5) OR KLV.REVERSE2 = HCP.SF_LSHR_NO_GET(T.EMP_CODE, 2)) WHERE KLV.LOOKUP_TYPE = 'DEPT_PEOPLE' AND KLV.ENABLED = 'Y' ORDER BY KLV.REVERSE2 DESC) WHERE ROWNUM = 1 ), V_CNT AS( SELECT DECODE(HPB.WORK_PLACE, 0, '一园', 1, '二园', 2, '三园', HPB.WORK_PLACE) AS PLANT, HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 14) DIV, HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 15) DEPT_NAME, HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 13) CLASS_NAME, COUNT(HPB.EMP_CODE) UNPEOPLE, SUM(HPB.ANNUAL_LEAVE) UNDAY, L.V_EMAIL || ';' || HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 9), 8) AS TOEMAIL, HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 10), 8) || ';' || HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 11), 8) AS CCEMAIL FROM V_DATA HPB JOIN DEPT_PEOPLE L ON HPB.EMP_CODE=L.EMP_CODE GROUP BY DECODE(HPB.WORK_PLACE, 0, '一园', 1, '二园', 2, '三园', HPB.WORK_PLACE), HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 14), HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 15), HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 13), L.V_EMAIL || ';' || HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 9), 8), HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 10), 8) || ';' || HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(HPB.EMP_CODE, 11), 8) UNION ALL SELECT '合计', '', '', '', UNPEOPLE, UNDAY, '', '' FROM (SELECT COUNT(EMP_CODE) UNPEOPLE, SUM(ANNUAL_LEAVE) UNDAY FROM V_DATA) WHERE UNDAY IS NOT NULL ) SELECT PLANT 厂区, DIV 处级, DEPT_NAME 部门名称, CLASS_NAME 课别名称, UNPEOPLE 未休人数, UNDAY 未休天数, TOEMAIL, CCEMAIL FROM V_CNT ORDER BY PLANT, DIV, DEPT_NAME, CLASS_NAME;
07-19
如下SQL执行时报错D.POINT_TIME,[Error] Execution (18: 80): ORA-01843: not a valid month,请协助修改, 并优化oracle如下SQL性能,提高执行效率和减少资源占用: WITH work_s AS ( SELECT A.EMP_CODE, A.EMPNAME, A.WORK_DATE, B.WS_NUMBER, B.WS_SIMPLE_NAME, C.LAST_TIME_TOTAL, D.POINT_TIME, D.ADV_TIME, D.OVER_TIME, D.WP_TYPE, D.IS_NEXT_DAY, -- 统一时间计算逻辑 CASE WHEN D.WP_TYPE = 2 AND D.IS_NEXT_DAY = 1 THEN TO_TIMESTAMP(to_char(A.WORK_DATE,'yyyy/mm/dd')||' '||to_char(D.POINT_TIME,'hh24:mi:ss')) + 1--INTERVAL '1' DAY ELSE TO_TIMESTAMP(to_char(A.WORK_DATE,'yyyy/mm/dd')||' '||to_char(D.POINT_TIME,'hh24:mi:ss')) END AS base_time, -- 优化OVERPOINT_TIME计算 TO_TIMESTAMP(to_char(A.WORK_DATE,'yyyy/mm/dd')||' '||to_char(D.POINT_TIME,'hh24:mi:ss')) + CASE WHEN D.WP_TYPE = 2 THEN (C.LAST_TIME_TOTAL + CASE WHEN B.WS_NUMBER IN ('035A','035B') THEN 90 WHEN B.WS_NUMBER = '005A' THEN 60 ELSE 120 END)/1440 ELSE 0 END + CASE WHEN D.IS_NEXT_DAY = 1 THEN 1 ELSE 0 END AS overpoint_time, -- 单独计算005A的特殊时间点 CASE WHEN B.WS_NUMBER = '005A' AND D.WP_TYPE = 2 THEN TO_TIMESTAMP(to_char(A.WORK_DATE,'yyyy/mm/dd')||' '||to_char(D.POINT_TIME,'hh24:mi:ss')) + (C.LAST_TIME_TOTAL + 240)/1440 END AS overpoint_time2 FROM HCP.v_clk_tz_emp_workday_info A JOIN HCP.v_clk_work_shift B ON A.WS_ID = B.ID JOIN HCP.v_clk_work_block C ON A.WS_ID = C.WS_ID JOIN HCP.v_clk_work_point D ON C.ID = D.WB_ID WHERE A.WORK_DATE = TRUNC(SYSDATE-1) ), attendance_data AS ( SELECT DECODE(HPB.WORK_PLACE, 0, 'LSP1', 1, 'LSP2', 2, 'LSP3') AS MASTER_NO, DECODE(HPB.WORK_PLACE, 0, '一园', 1, '二园', 2, '三园') AS WORK_PLACE, HPB.EMPCODE, HPB.EMPNAME, FF.FGT02, FF.FGT08, SUBSTR(FF.FGT08,3,1) AS card_type, HPB.RANK_NAME, HPB.ORG_NAME, DECODE(H.SALARY_TYPE,1,'月薪',2,'计时',3,'计件') AS SALARY_TYPE FROM FINGER5.FGT_FILE FF JOIN HCP.TZ_EMP_IN HPB ON FF.FGT10 = HPB.EMPCODE JOIN HCP.v_clk_tz_employee H ON FF.FGT10 = H.EMPCODE JOIN work_s A ON A.EMP_CODE = FF.FGT10 WHERE FF.FGT02 >= TRUNC(SYSDATE-1) AND FF.FGT02 < TRUNC(SYSDATE-1)+1 -- 优化日期范围 AND FF.FGT03 <> '4' AND LENGTH(FF.FGT08) = 5 AND SUBSTR(FF.FGT08,3,1) IN ('1','2') AND ( (SUBSTR(FF.FGT08,3,1) = '1' AND A.WP_TYPE = 1 AND FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE) OR (SUBSTR(FF.FGT08,3,1) = '2' AND A.WP_TYPE = 2 AND ( CASE WHEN (H.SALARY_TYPE = 1 AND FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE) THEN 1 --OR WHEN H.SALARY_TYPE <> 1 AND (A.WS_NUMBER = '005A' AND ( FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE OR FF.FGT02 BETWEEN A.overpoint_time AND A.overpoint_time + INTERVAL '1' MINUTE OR FF.FGT02 BETWEEN A.overpoint_time2 AND A.overpoint_time2 + INTERVAL '1' MINUTE)) THEN 1 --OR WHEN H.SALARY_TYPE <> 1 AND (FF.FGT02 BETWEEN A.base_time AND A.base_time + INTERVAL '1' MINUTE OR FF.FGT02 BETWEEN A.overpoint_time AND A.overpoint_time + INTERVAL '1' MINUTE) THEN 1 END )=1) ) ), attendance_filtered AS ( SELECT MASTER_NO, WORK_PLACE, EMPCODE, EMPNAME, FGT02, FGT08, card_type, DECODE(card_type, '1', '上班卡', '2', '下班卡') AS status, RANK_NAME, ORG_NAME, SALARY_TYPE, ROW_NUMBER() OVER ( PARTITION BY EMPCODE, card_type ORDER BY FGT02 ASC ) AS rank -- 按员工和打卡类型分区,取最早记录 FROM attendance_data ), tz_opr AS ( SELECT KLV.MEANING, KLV.DESCRIPTION, KLV.REVERSE2, KLV.REVERSE1, KLV.REVERSE3 IP, KLV.REVERSE4 FROM HCP.KS_LOOKUP_VALUE KLV WHERE KLV.LOOKUP_TYPE = 'KQ_SEPARATE_MACHINE' AND KLV.ENABLED = 'Y' ) SELECT MASTER_NO, WORK_PLACE AS MASTER_NAME, EMPCODE AS ID_NO_SZ, EMPNAME AS NAME_SZ, FGT02 AS RECORDTIME, FGT08 AS MACHINE_NO, trunc(SYSDATE-1) AS CDAY, -- 修改为TRUNC确保纯日期输出 A.REVERSE4 AS MACHINE_LOC, status AS SHIFTTYPE, RANK_NAME AS TITLE_NO, HCP.SF_LSHR_NO_GET(EMPCODE, 18) AS TITLE_NAME, SALARY_TYPE, HCP.SF_LSHR_NO_GET(EMPCODE, 2) AS SEGMENT_NO, HCP.SF_LSHR_NO_GET(EMPCODE, 13) AS SEGMENT_NAME, SUBSTR(HCP.SF_LSHR_NO_GET(EMPCODE, 15), LENGTH(HCP.SF_LSHR_NO_GET(EMPCODE, 15))-5) AS DEPT_NO, -- 取后6位 HCP.SF_LSHR_NO_GET(EMPCODE, 15) AS DEPT_NAME, HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(EMPCODE, 9), 8) AS TOEMAIL, HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(EMPCODE, 10), 8) || ';' || HCP.SF_LSHR_NO_GET(HCP.SF_LSHR_NO_GET(EMPCODE, 11), 8) AS CCEMAIL, '' AS TEMP_COMPANY FROM attendance_filtered JOIN tz_opr A ON FGT08 = A.MEANING WHERE rank = 1 -- 取每个员工每个打卡类型的最早记录 ORDER BY status, FGT02; -- 按打卡类型和时间排序
08-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值