加班问题的SQL(Teradata)解法

题目:
公司规定一周内加班总和最多只能12个小时,多余的要去掉,去掉的规则是:某天加班超过1H的才能去,而且是依次大致平均的去除,(最小单位是1小时)
举例:
日期 工号 加班小时
周一 A001  6
周二 A001  2
周三 A001  1
周四 A001  5
周五 A001  7
----------------
  共计加班:21H,超出9H

算法:
从周一开始依次删减,每天减1H(如果当天的加班时间>1H),一轮后如果还不够,再继续下一轮,直到刚好为12H为止(只对超过12H的而言)
最后的结果应该是:
日期 工号 加班小时
周一 A001  3  --减了3次
周二 A001  1  --减了1次
周三 A001  1  --减了0次
周四 A001  2  --减了3次
周五 A001  5  --减了2次
-----------------------
以上只列具体某一个人的,公司有好几千人,

实现要求:
用SQL语句实现,考虑到效率问题规定:
1.不能用游标
2.不能用循环
其它方法都可以

 

答案:

建立测试环境:
测试表:
CREATE SET TABLE TESTDB.testrecursive ,NO FALLBACK ,
     NO BEFORE JOURNAL,
     NO AFTER JOURNAL,
     CHECKSUM = DEFAULT
     (
      wkd CHAR(10) CHARACTER SET LATIN NOT CASESPECIFIC,
      wkno CHAR(10) CHARACTER SET LATIN NOT CASESPECIFIC,
      wkhour INTEGER)
PRIMARY INDEX ( wkd );

查询语句:
WITH RECURSIVE
Workload_Week(Worker_No, W1_hour, W2_hour, W3_hour, W4_hour, W5_hour, Total, Indice, Depth)
AS
(
SELECT
  Wkno AS Worker_No
, MAX(CASE WHEN WKD = 'W1' THEN wkhour END) AS W1_hour
, MAX(CASE WHEN WKD = 'W2' THEN wkhour END) AS W2_hour
, MAX(CASE WHEN WKD = 'W3' THEN wkhour END) AS W3_hour
, MAX(CASE WHEN WKD = 'W4' THEN wkhour END) AS W4_hour
, MAX(CASE WHEN WKD = 'W5' THEN wkhour END) AS W5_hour
, ( W1_hour + W2_hour + W3_hour + W4_hour + W5_hour ) AS Total
, 1
, 0
FROM TESTDB.testrecursive
GROUP BY 1
UNION ALL
SELECT
  Worker_No
, CASE WHEN W1_hour > 1 AND Indice = 1 THEN W1_hour - 1 ELSE W1_hour END AS W1_hour_NEW
, CASE WHEN W2_hour > 1 AND Indice = 2 THEN W2_hour - 1 ELSE W2_hour END AS W2_hour_NEW
, CASE WHEN W3_hour > 1 AND Indice = 3 THEN W3_hour - 1 ELSE W3_hour END AS W3_hour_NEW
, CASE WHEN W4_hour > 1 AND Indice = 4 THEN W4_hour - 1 ELSE W4_hour END AS W4_hour_NEW
, CASE WHEN W5_hour > 1 AND Indice = 5 THEN W5_hour - 1 ELSE W5_hour END AS W5_hour_NEW
, ( W1_hour_NEW + W2_hour_NEW + W3_hour_NEW + W4_hour_NEW + W5_hour_NEW ) AS Total_NEW
, indice MOD 5 + 1
, depth + 1
FROM Workload_Week
WHERE total > 12
)
SELECT
  'W1' AS WKD
, Worker_No AS WKNO
, W1_hour AS WKHOUR
 FROM Workload_Week
 WHERE total = 12
 UNION ALL
 SELECT
  'W2' AS WKD
, Worker_No AS WKNO
, W2_hour AS WKHOUR
 FROM Workload_Week
 WHERE total = 12
 UNION ALL
 SELECT
  'W3' AS WKD
, Worker_No AS WKNO
, W3_hour AS WKHOUR
 FROM Workload_Week
 WHERE total = 12
 UNION ALL
 SELECT
  'W4' AS WKD
, Worker_No AS WKNO
, W4_hour AS WKHOUR
 FROM Workload_Week
 WHERE total = 12
 UNION ALL
 SELECT
  'W5' AS WKD
, Worker_No AS WKNO
, W5_hour AS WKHOUR
 FROM Workload_Week
 WHERE total = 12
;

解析:

本例虽然语法上使用递归查询语句WITH RECURSIVE 但是还牵涉到行列转换的技术。对开发者的要求较高。

你可能感兴趣的:(大数据,Teradata,SQL)