From 646d568cd394bd93473dd4cf8fdeb4c97c3cd9e5 Mon Sep 17 00:00:00 2001 From: Alex Zaw Date: Wed, 25 Feb 2026 23:06:06 +0000 Subject: [PATCH] Update Function SFP_GET_OEE_DETAILS --- RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql | 409 +++++++++++++++++++++- 1 file changed, 408 insertions(+), 1 deletion(-) diff --git a/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql b/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql index 0e49bb4..3eb35ec 100644 --- a/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql +++ b/RESTAPI/Functions/SFP_GET_OEE_DETAILS.sql @@ -1 +1,408 @@ -@@\@^@ % %@@@@Kmmm@M@ %m@M]@]@ %@M]@@@ %@@ %@Kmmm@ %@@ %@@@ %@@@@ %@@@@~@\@k@ %@~@\@k@ %@~@\@k@ %@~@Mk@k@]@k@ %@~@\@k@ %@~@\@k@ %@~@\@@@ %@ %@@@M@@]@@}}@^@ %@@@M@@]@@}}@^@ %``@ř@@@ %@m@@M@@]@@}}@^@ %@m@@@@^@ %@m@@M@@]@@}}@^@ %@mm@@@@^@ %@mm@@@@^@ %``@Ö@@@@@ %@@@@@}}@@``@ɕ@@ %@ %@m@~@}}@^@ %@@@@m@~@m@^@ %@mm@~@@^@ %@mm@~@@^@ %@^@ %@@@@@}}@@``@դ@@@@ %@ %@m@~@}}@^@ %@@@@m@~@m@^@ %@mm@~@@^@ %@mm@~@@^@ %@^@ %@@@@@}}@@``@Ֆ@@@ %@ %@m@~@}}@^@ %@m@~@}Ֆ@@@@@@}@^@ %@mm@~@@^@ %@mm@~@@^@ %@^@ %@@@@@}}@@``@Ֆ@@ %@ %@m@~@}}@^@ %@@@@m@~@m@^@ %@mm@~@@^@ %@mm@~@@^@ %@^@ %@@@@@}}@@``@ւ@@@ %@ %@m@~@}}@^@ %@@@@m@~@m@^@ %@mm@~@@^@ %@mm@~@@^@ %@^@ %@@@@@ %@ %@@@@ %m@~@m@k@ %m@~@mm@k@m@~@m@^@ %@mm@~@@^@ %@mm@~@@^@ %@^@ %@@K@m@M@m@]@@M@}}@k@}}@k@}}@]@@m@~@ %@@K@m@M@m@]@ %@}}@@m@M@m@k@}[K}@]@ %@}}@@m@M@m@k@}[}@]@ %@}}@@@M@m@k@}}@k@}}@]@ %@@M@m@]@ %@^@ %@@^@ %@@~@m@^@ %@@~@@K@mm@M@@]@^@ %``@偓@@@@ %@@~@}}@ %@@@@@ %@ %m@M@ %}}@z@m@M@ %}m}@z@ \ No newline at end of file +SET PATH *LIBL ; + +CREATE OR REPLACE FUNCTION RESTAPI.SFP_GET_OEE_DETAILS ( + IN_PARM CLOB(2147483647) ) + RETURNS CLOB(2147483647) + LANGUAGE SQL + SPECIFIC RESTAPI.SFP_GET_OEE_DETAILS + NOT DETERMINISTIC + MODIFIES SQL DATA + CALLED ON NULL INPUT + SET OPTION ALWBLK = *ALLREAD , + ALWCPYDTA = *OPTIMIZE , + COMMIT = *NONE , + DECRESULT = (31, 31, 00) , + DYNDFTCOL = *NO , + DYNUSRPRF = *USER , + SRTSEQ = *HEX + BEGIN +DECLARE ENV VARCHAR ( 20 ) DEFAULT '' ; +DECLARE LL VARCHAR ( 1024 ) DEFAULT '' ; +-- Error handling variables +DECLARE V_SQLSTATE CHAR ( 5 ) DEFAULT '00000' ; +DECLARE V_SQLCODE INTEGER DEFAULT 0 ; +DECLARE V_ERRMSG VARCHAR ( 500 ) DEFAULT '' ; +DECLARE V_HTTP_STATUS INTEGER DEFAULT 200 ; +DECLARE V_HAS_ERROR INTEGER DEFAULT 0 ; +-- Continue handlers for error capture +DECLARE CONTINUE HANDLER FOR SQLSTATE '22007' -- Invalid datetime +BEGIN +SET V_SQLSTATE = '22007' ; +GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; +SET V_HTTP_STATUS = 400 ; +SET V_HAS_ERROR = 1 ; +END ; +DECLARE CONTINUE HANDLER FOR SQLSTATE '22003' -- Numeric out of range +BEGIN +SET V_SQLSTATE = '22003' ; +GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; +SET V_HTTP_STATUS = 400 ; +SET V_HAS_ERROR = 1 ; +END ; +DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' -- No data found +BEGIN +SET V_SQLSTATE = '02000' ; +SET V_ERRMSG = 'No data found for the specified criteria' ; +SET V_HTTP_STATUS = 404 ; +SET V_HAS_ERROR = 1 ; +END ; +DECLARE CONTINUE HANDLER FOR SQLSTATE '42501' -- Not authorized +BEGIN +SET V_SQLSTATE = '42501' ; +GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; +SET V_HTTP_STATUS = 403 ; +SET V_HAS_ERROR = 1 ; +END ; +DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' -- Object not found +BEGIN +SET V_SQLSTATE = '42704' ; +GET DIAGNOSTICS CONDITION 1 V_ERRMSG = MESSAGE_TEXT ; +SET V_HTTP_STATUS = 404 ; +SET V_HAS_ERROR = 1 ; +END ; +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION +BEGIN +GET DIAGNOSTICS CONDITION 1 +V_SQLSTATE = RETURNED_SQLSTATE , +V_SQLCODE = DB2_RETURNED_SQLCODE , V_ERRMSG = MESSAGE_TEXT ; +SET V_HTTP_STATUS = 500 ; +SET V_HAS_ERROR = 1 ; +END ; +WHILE CISTOOLS . JSON_TYPE ( IN_PARM ) IN ( 'object' , 'array' , 'string' ) DOSET IN_PARM = +CASE CISTOOLS . JSON_TYPE ( IN_PARM ) +WHEN 'object' THEN JSON_VALUE ( IN_PARM , '$.env' ) +WHEN 'array' THEN JSON_VALUE ( IN_PARM , '$[0]' ) +WHEN 'string' THEN REPLACE ( IN_PARM , '"' , '' ) +ELSE TRIM ( IN_PARM ) +END ; +END WHILE ; +SET ENV = IN_PARM ; +SET LL = CISTOOLS . SET_LIBRARY_LIST ( ENV ) ; +-- Validate environment was set +IF ENV = '' +OR ENV IS NULL THEN +RETURN +JSON_OBJECT ( +'error' : JSON_OBJECT ( +'http_status' : 400 , 'sqlstate' : '22001' , +'message' : 'Environment parameter is required' +) +) ; +END IF ; +-- Check for errors from library list setup +IF V_HAS_ERROR = 1 THEN +RETURN +JSON_OBJECT ( +'error' : JSON_OBJECT ( +'http_status' : V_HTTP_STATUS , 'sqlstate' : V_SQLSTATE , +'message' : V_ERRMSG +) +) ; +END IF ; +RETURN +WITH BOUNDS AS ( +SELECT CURRENT_DATE AS FOR_DATE , 1 AS WEEK_END_DOW , +2 AS WEEK_START_DOW , +ZONED ( CURRENT_DATE ) AS YYYYMMDD_FOR , +ZONED ( +LAST_DAY ( ADD_MONTHS ( CURRENT_DATE , - 1 ) ) + 1 DAY ) +AS YYYYMMDD_MONTH_FROM , +ZONED ( LAST_DAY ( CURRENT_DATE ) ) +AS YYYYMMDD_MONTH_THRU , +DAYOFWEEK ( CURRENT_DATE ) AS DOW_FOR +FROM SYSIBM . SYSDUMMY1 +) , +WEEK_CALC AS ( +SELECT B . * , +MOD ( B . DOW_FOR - B . WEEK_START_DOW + 7 , 7 ) +AS DELTA_DAYS +FROM BOUNDS B +) , +RANGES AS ( +SELECT 'M' AS RANGE_TYPE , +( YYYYMMDD_MONTH_FROM - 19000000 ) AS FROM_CY , +( YYYYMMDD_MONTH_THRU - 19000000 ) AS THRU_CY +FROM WEEK_CALC +UNION ALL +SELECT 'W' AS RANGE_TYPE , +( ( YEAR ( FOR_DATE - DELTA_DAYS DAYS ) * 10000 + +MONTH ( FOR_DATE - DELTA_DAYS DAYS ) * 100 + +DAY ( FOR_DATE - DELTA_DAYS DAYS ) ) - 19000000 ) +AS FROM_CY , ( YYYYMMDD_FOR - 19000000 ) AS THRU_CY +FROM WEEK_CALC +UNION ALL +SELECT 'D' AS RANGE_TYPE , +( YYYYMMDD_FOR - 19000000 ) AS FROM_CY , +( YYYYMMDD_FOR - 19000000 ) AS THRU_CY +FROM WEEK_CALC +) , +-- Work center level data +WC_DATA AS ( +SELECT R . RANGE_TYPE , TRIM ( P . KIGRP1 ) AS PLANT , +TRIM ( P . KIGRP2 ) AS DEPT , TRIM ( P . KIWKCTR ) AS WC , +SUM ( P . KIUP ) AS UP_SEC , SUM ( P . KISDWN ) AS SDWN_SEC , +SUM ( P . KIUDWN ) AS UDWN_SEC , SUM ( P . KIGAP ) AS GAP_SEC , +SUM ( P . KIUA ) AS UA_SEC , SUM ( P . KIRCVD ) AS GOOD_QTY , +SUM ( P . KISCRP ) AS BAD_QTY , +SUM ( P . KIEXPT ) AS TARGET_QTY , +SUM ( P . KIARUN ) AS ARUN_SEC , +SUM ( P . KIASET ) AS ASET_SEC , +SUM ( P . KIASDW ) AS ASDW_SEC , SUM ( P . KIAUDW ) AS AUDW_SEC +FROM RANGES R +JOIN SFCPERI P +ON P . KIDATE BETWEEN R . FROM_CY AND R . THRU_CY +GROUP BY R . RANGE_TYPE , P . KIGRP1 , P . KIGRP2 , P . KIWKCTR +) , +-- Calculate metrics at WC level +WC_CALC AS ( +SELECT RANGE_TYPE , PLANT , DEPT , WC , UP_SEC , SDWN_SEC , +UDWN_SEC , GAP_SEC , UA_SEC , GOOD_QTY , BAD_QTY , +TARGET_QTY , ARUN_SEC , ASET_SEC , ASDW_SEC , AUDW_SEC , +INT ( +( COALESCE ( +( DECFLOAT ( UP_SEC - UDWN_SEC - GAP_SEC ) / +NULLIF ( DECFLOAT ( UP_SEC ) , 0 ) ) , 0 ) * +COALESCE ( +( DECFLOAT ( GOOD_QTY + BAD_QTY ) / +NULLIF ( DECFLOAT ( TARGET_QTY ) , 0 ) ) , 0 ) * +COALESCE ( +( DECFLOAT ( GOOD_QTY ) / +NULLIF ( DECFLOAT ( GOOD_QTY + BAD_QTY ) , 0 ) +) , 0 ) * 100 ) + 0.5 ) AS OEE_PCT , +DEC ( +DEC ( +UP_SEC + SDWN_SEC + UDWN_SEC + GAP_SEC , 31 , +10 ) / 3600 , 13 , 2 ) AS ELAPSED_HRS , +DEC ( +DEC ( +ARUN_SEC + ASET_SEC + ASDW_SEC + AUDW_SEC , 31 , +10 ) / 3600 , 13 , 2 ) AS APPLIED_HRS , +DEC ( DEC ( UP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) +AS TIME_UP_HRS , +DEC ( +DEC ( +SDWN_SEC + UDWN_SEC + GAP_SEC + UA_SEC , 31 , +10 ) / 3600 , 13 , 2 ) AS DOWN_TOTAL_HRS , +DEC ( DEC ( SDWN_SEC , 31 , 10 ) / 3600 , 13 , 2 ) +AS SCHED_DOWN_HRS , +DEC ( DEC ( UDWN_SEC , 31 , 10 ) / 3600 , 13 , 2 ) +AS UNSCHED_DOWN_HRS , +DEC ( DEC ( GAP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) AS GAP_HRS , +DEC ( DEC ( UA_SEC , 31 , 10 ) / 3600 , 13 , 2 ) +AS UNAVAIL_HRS , +DEC ( GOOD_QTY , 31 , 2 ) AS GOOD_PARTS , +DEC ( BAD_QTY , 31 , 2 ) AS BAD_PARTS , +DEC ( TARGET_QTY , 31 , 2 ) AS TARGET_PARTS , +INT ( +( COALESCE ( +( DECFLOAT ( UP_SEC - UDWN_SEC - GAP_SEC ) / +NULLIF ( DECFLOAT ( UP_SEC ) , 0 ) ) , 0 ) * 100 ) + +0.5 ) AS AVAILABILITY_PCT , +INT ( +( COALESCE ( +( DECFLOAT ( GOOD_QTY + BAD_QTY ) / +NULLIF ( DECFLOAT ( TARGET_QTY ) , 0 ) ) , 0 ) * 100 ) ++ 0.5 ) AS PERFORMANCE_PCT , +INT ( +( COALESCE ( +( DECFLOAT ( GOOD_QTY ) / +NULLIF ( DECFLOAT ( GOOD_QTY + BAD_QTY ) , 0 ) ) , +0 ) * 100 ) + 0.5 ) AS QUALITY_PCT , +DEC ( DEC ( ARUN_SEC , 31 , 10 ) / 3600 , 13 , 2 ) AS RUN_HRS , +DEC ( DEC ( ASET_SEC , 31 , 10 ) / 3600 , 13 , 2 ) +AS SETUP_HRS , +DEC ( DEC ( ASDW_SEC , 31 , 10 ) / 3600 , 13 , 2 ) +AS APPL_SDWN_HRS , +DEC ( DEC ( AUDW_SEC , 31 , 10 ) / 3600 , 13 , 2 ) +AS APPL_UDWN_HRS +FROM WC_DATA +) , +-- Pre-aggregate totals at each level to avoid join multiplication +DEPT_TOTALS AS ( +SELECT RANGE_TYPE , PLANT , DEPT , SUM ( UP_SEC ) AS UP_SEC , +SUM ( SDWN_SEC ) AS SDWN_SEC , +SUM ( UDWN_SEC ) AS UDWN_SEC , SUM ( GAP_SEC ) AS GAP_SEC , +SUM ( GOOD_QTY ) AS GOOD_QTY , SUM ( BAD_QTY ) AS BAD_QTY , +SUM ( TARGET_QTY ) AS TARGET_QTY +FROM WC_DATA +GROUP BY RANGE_TYPE , PLANT , DEPT +) , +PLANT_TOTALS AS ( +SELECT RANGE_TYPE , PLANT , SUM ( UP_SEC ) AS UP_SEC , +SUM ( SDWN_SEC ) AS SDWN_SEC , +SUM ( UDWN_SEC ) AS UDWN_SEC , SUM ( GAP_SEC ) AS GAP_SEC , +SUM ( GOOD_QTY ) AS GOOD_QTY , SUM ( BAD_QTY ) AS BAD_QTY , +SUM ( TARGET_QTY ) AS TARGET_QTY +FROM WC_DATA +GROUP BY RANGE_TYPE , PLANT +) , +GRAND_TOTALS AS ( +SELECT RANGE_TYPE , SUM ( UP_SEC ) AS UP_SEC , +SUM ( SDWN_SEC ) AS SDWN_SEC , +SUM ( UDWN_SEC ) AS UDWN_SEC , SUM ( GAP_SEC ) AS GAP_SEC , +SUM ( GOOD_QTY ) AS GOOD_QTY , SUM ( BAD_QTY ) AS BAD_QTY , +SUM ( TARGET_QTY ) AS TARGET_QTY +FROM WC_DATA +GROUP BY RANGE_TYPE +) , +-- Build workcenter JSON objects +WC_JSON AS ( +SELECT RANGE_TYPE , PLANT , DEPT , +JSON_OBJECT ( +'workcenterName' : WC , 'oeePercentage' : OEE_PCT , +'elapsedHours' : ELAPSED_HRS , +'appliedHours' : APPLIED_HRS , +'timeUpHours' : TIME_UP_HRS , +'totalDownHours' : DOWN_TOTAL_HRS , +'scheduledDownHours' : SCHED_DOWN_HRS , +'unscheduledDownHours' : UNSCHED_DOWN_HRS , +'gapHours' : GAP_HRS , +'unavailableHours' : UNAVAIL_HRS , +'goodParts' : GOOD_PARTS , 'badParts' : BAD_PARTS , +'targetParts' : TARGET_PARTS , +'availabilityPercentage' : AVAILABILITY_PCT , +'performancePercentage' : PERFORMANCE_PCT , +'qualityPercentage' : QUALITY_PCT , +'runHours' : RUN_HRS , 'setupHours' : SETUP_HRS , +'appliedScheduledDownHours' : APPL_SDWN_HRS , +'appliedUnscheduledDownHours' : APPL_UDWN_HRS +) AS WC_OBJ +FROM WC_CALC +) , +-- Build dept JSON with pre-aggregated totals +DEPT_JSON AS ( +SELECT W . RANGE_TYPE , W . PLANT , W . DEPT , +JSON_OBJECT ( +'departmentName' : W . DEPT , 'oeePercentage' : INT ( +( COALESCE ( +( DECFLOAT ( +T . UP_SEC - T . UDWN_SEC - T . GAP_SEC ) / +NULLIF ( DECFLOAT ( T . UP_SEC ) , 0 ) ) , 0 ) * +COALESCE ( +( DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) / +NULLIF ( DECFLOAT ( T . TARGET_QTY ) , 0 ) ) , +0 ) * +COALESCE ( +( DECFLOAT ( T . GOOD_QTY ) / +NULLIF ( +DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) , +0 ) ) , 0 ) * 100 ) + 0.5 ) , +'elapsedHours' : DEC ( +DEC ( +T . UP_SEC + T . SDWN_SEC + T . UDWN_SEC + +T . GAP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , +'timeUpHours' : DEC ( +DEC ( T . UP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , +'goodParts' : DEC ( T . GOOD_QTY , 31 , 2 ) , +'targetParts' : DEC ( T . TARGET_QTY , 31 , 2 ) , +'workcenters' : JSON_ARRAYAGG ( +W . WC_OBJ FORMAT JSON +ORDER BY W . DEPT +) +) AS DEPT_OBJ +FROM WC_JSON W +JOIN DEPT_TOTALS T +ON W . RANGE_TYPE = T . RANGE_TYPE +AND W . PLANT = T . PLANT +AND W . DEPT = T . DEPT +GROUP BY W . RANGE_TYPE , W . PLANT , W . DEPT , T . UP_SEC , +T . SDWN_SEC , T . UDWN_SEC , T . GAP_SEC , T . GOOD_QTY , +T . BAD_QTY , T . TARGET_QTY +) , +-- Build plant JSON with pre-aggregated totals +PLANT_JSON AS ( +SELECT D . RANGE_TYPE , D . PLANT , +JSON_OBJECT ( +'plantName' : D . PLANT , 'oeePercentage' : INT ( +( COALESCE ( +( DECFLOAT ( +T . UP_SEC - T . UDWN_SEC - T . GAP_SEC ) / +NULLIF ( DECFLOAT ( T . UP_SEC ) , 0 ) ) , 0 ) * +COALESCE ( +( DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) / +NULLIF ( DECFLOAT ( T . TARGET_QTY ) , 0 ) ) , +0 ) * +COALESCE ( +( DECFLOAT ( T . GOOD_QTY ) / +NULLIF ( +DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) , +0 ) ) , 0 ) * 100 ) + 0.5 ) , +'elapsedHours' : DEC ( +DEC ( +T . UP_SEC + T . SDWN_SEC + T . UDWN_SEC + +T . GAP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , +'timeUpHours' : DEC ( +DEC ( T . UP_SEC , 31 , 10 ) / 3600 , 13 , 2 ) , +'goodParts' : DEC ( T . GOOD_QTY , 31 , 2 ) , +'targetParts' : DEC ( T . TARGET_QTY , 31 , 2 ) , +'departments' : JSON_ARRAYAGG ( +D . DEPT_OBJ FORMAT JSON +ORDER BY D . DEPT +) +) AS PLANT_OBJ +FROM DEPT_JSON D +JOIN PLANT_TOTALS T +ON D . RANGE_TYPE = T . RANGE_TYPE +AND D . PLANT = T . PLANT +GROUP BY D . RANGE_TYPE , D . PLANT , T . UP_SEC , T . SDWN_SEC , +T . UDWN_SEC , T . GAP_SEC , T . GOOD_QTY , T . BAD_QTY , +T . TARGET_QTY +) , +GROUPED AS ( +SELECT P . RANGE_TYPE , +JSON_OBJECT ( +'rangeLabel' : +CASE P . RANGE_TYPE +WHEN 'M' THEN 'Monthly' +WHEN 'W' THEN 'Weekly' +WHEN 'D' THEN 'Daily' +END , +'generatedAt' : TO_CHAR ( +CURRENT_TIMESTAMP , 'YYYY-MM-DD HH24:MI:SS' +) , 'totalOeePercentage' : INT ( +( COALESCE ( +( DECFLOAT ( +T . UP_SEC - T . UDWN_SEC - T . GAP_SEC ) / +NULLIF ( DECFLOAT ( T . UP_SEC ) , 0 ) ) , 0 ) * +COALESCE ( +( DECFLOAT ( T . GOOD_QTY + T . BAD_QTY ) / +NULLIF ( DECFLOAT ( T . TARGET_QTY ) , 0 ) +) , 0 ) * +COALESCE ( +( DECFLOAT ( T . GOOD_QTY ) / +NULLIF ( +DECFLOAT ( +T . GOOD_QTY + T . BAD_QTY ) , 0 ) +) , 0 ) * 100 ) + 0.5 ) , +'plants' : JSON_ARRAYAGG ( +P . PLANT_OBJ FORMAT JSON +ORDER BY P . PLANT +) +) AS JSON_DATA +FROM PLANT_JSON P +JOIN GRAND_TOTALS T +ON P . RANGE_TYPE = T . RANGE_TYPE +GROUP BY P . RANGE_TYPE , T . UP_SEC , T . SDWN_SEC , +T . UDWN_SEC , T . GAP_SEC , T . GOOD_QTY , +T . BAD_QTY , T . TARGET_QTY +ORDER BY +CASE P . RANGE_TYPE +WHEN 'D' THEN 3 +WHEN 'W' THEN 2 +ELSE 1 +END ) SELECT JSON_OBJECT ( +'ranges' VALUE JSON_ARRAYAGG ( +JSON_DATA FORMAT JSON +) +) +FROM GROUPED ; +END ; + +GRANT ALTER , EXECUTE +ON SPECIFIC FUNCTION RESTAPI.SFP_GET_OEE_DETAILS +TO AMAPICS WITH GRANT OPTION ; + +GRANT EXECUTE +ON SPECIFIC FUNCTION RESTAPI.SFP_GET_OEE_DETAILS +TO PUBLIC ; +