From df516a7ad9f0c11b7b94383ed90b083de0d97a10 Mon Sep 17 00:00:00 2001 From: Alex Zaw Date: Wed, 25 Feb 2026 23:05:59 +0000 Subject: [PATCH] Update Function SFP_GET_HOURLY_OEE --- RESTAPI/Functions/SFP_GET_HOURLY_OEE.sql | 821 ++++++++++++++++++++++- 1 file changed, 820 insertions(+), 1 deletion(-) diff --git a/RESTAPI/Functions/SFP_GET_HOURLY_OEE.sql b/RESTAPI/Functions/SFP_GET_HOURLY_OEE.sql index 14b8803..8e18d4f 100644 --- a/RESTAPI/Functions/SFP_GET_HOURLY_OEE.sql +++ b/RESTAPI/Functions/SFP_GET_HOURLY_OEE.sql @@ -1 +1,820 @@ -@@\@^@ % %@@@@Kmmm@M@ %m@M]@]@ %@M]@@@ %@@ %@Kmmm@ %@@ %@@@ %@@@@ %@@@@~@\@k@ %@~@\@k@ %@~@\@k@ %@~@Mk@k@]@k@ %@~@\@k@ %@~@\@k@ %@~@\@@@ %@ %@@@M@@]@@}}@^@ %@m@@^@ %@mm@@M@@]@@}}@^@ %@m@@M@@]@@}}@^@ %@m@@M@@]@@}}@^@ %@mm@@M@@k@@]@@@^@ %@mmm@@M@@k@@]@@@^@ %@@@M@@]@@}}@^@ %@mm@@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@~@@^@ %@^@ %``@ׁ@@@@M@@@@ɕmׁ]@ %@mm@~@@M@m@M@m@k@}[K}@]@k@}}@]@^@ %@m@~@@M@m@M@m@k@}[K}@]@k@}}@]@^@ %@m@~@ \ No newline at end of file +SET PATH *LIBL ; + +CREATE OR REPLACE FUNCTION RESTAPI.SFP_GET_HOURLY_OEE ( + IN_PARM CLOB(2147483647) ) + RETURNS CLOB(2147483647) + LANGUAGE SQL + SPECIFIC RESTAPI.SFP_GET_HOURLY_OEE + 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 V_DATE DATE ; +DECLARE V_DATE_STR VARCHAR ( 10 ) DEFAULT '' ; +DECLARE V_WC VARCHAR ( 5 ) DEFAULT '' ; +DECLARE V_SITE VARCHAR ( 3 ) DEFAULT '' ; +DECLARE V_DATE_CY DECIMAL ( 7 , 0 ) DEFAULT 0 ; +DECLARE V_DATE_PRIOR_CY DECIMAL ( 7 , 0 ) DEFAULT 0 ; +DECLARE LL VARCHAR ( 1024 ) DEFAULT '' ; +DECLARE V_IN_PARM CLOB ( 2 G ) 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 ; +-- Parse input parameters first (before env extraction modifies In_Parm) +SET V_DATE_STR = COALESCE ( JSON_VALUE ( IN_PARM , '$.date' ) , '' ) ; +SET V_WC = COALESCE ( JSON_VALUE ( IN_PARM , '$.workcenter' ) , '' ) ; +SET V_SITE = COALESCE ( JSON_VALUE ( IN_PARM , '$.site' ) , '' ) ; +-- Parse date - set to Current_Date if not provided +IF V_DATE_STR <> '' THEN +SET V_DATE = DATE ( V_DATE_STR ) ; +ELSE +SET V_DATE = CURRENT_DATE ; +END IF ; +-- Extract env handling all input formats (object, array, string) +SET V_IN_PARM = IN_PARM ; +WHILE CISTOOLS . JSON_TYPE ( V_IN_PARM ) IN ( 'object' , 'array' , 'string' ) +DO +SET V_IN_PARM = +CASE CISTOOLS . JSON_TYPE ( V_IN_PARM ) +WHEN 'object' THEN JSON_VALUE ( V_IN_PARM , '$.env' ) +WHEN 'array' THEN JSON_VALUE ( V_IN_PARM , '$[0]' ) +WHEN 'string' THEN REPLACE ( V_IN_PARM , '"' , '' ) +ELSE TRIM ( V_IN_PARM ) +END ; +END WHILE ; +SET ENV = V_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 ; +-- Calculate CYYMMDD dates +SET V_DATE_CY = ZONED ( V_DATE ) - 19000000 ; +SET V_DATE_PRIOR_CY = ZONED ( V_DATE - 1 DAY ) - 19000000 ; +RETURN +WITH +-- ========== RUN TRANSACTIONS (ON/OF) ========== +RUN_ON AS ( +SELECT T . ORDNO , T . OPSEQ , T . ITNBR , T . WKCTR , +COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , +T . TDATE AS ON_DATE , T . TTIME AS ON_TIME , T . RUNCD , +M . STID , +TO_DATE ( +ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || +LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) +AS ON_TS , +ROW_NUMBER ( ) OVER ( +PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( +T . EMPNO , T . BADGE ) , T . RUNCD , T . WKCTR +ORDER BY T . TDATE , T . TTIME +) AS SEQ +FROM MOTRAN T +JOIN MOMAST M +ON T . ORDNO = M . ORDNO +WHERE T . TCODE = 'ON' +AND T . RUNCD = 'R' +AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) +AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) +AND T . ACREC = 'A' +AND T . TDATE BETWEEN V_DATE_PRIOR_CY AND V_DATE_CY +) , +RUN_OFF AS ( +SELECT T . ORDNO , T . OPSEQ , T . WKCTR , +COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , +T . TDATE AS OFF_DATE , T . TTIME AS OFF_TIME , T . QTCOM , +T . QTSCP , T . RUNCD , M . STID , +TO_DATE ( +ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || +LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) +AS OFF_TS , +ROW_NUMBER ( ) OVER ( +PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( +T . EMPNO , T . BADGE ) , T . RUNCD , T . WKCTR +ORDER BY T . TDATE , T . TTIME +) AS SEQ +FROM MOTRAN T +JOIN MOMAST M +ON T . ORDNO = M . ORDNO +WHERE T . TCODE = 'OF' +AND T . RUNCD = 'R' +AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) +AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) +AND T . ACREC = 'A' +AND T . TDATE = V_DATE_CY +) , +CURRENT_END AS ( +SELECT +CASE +WHEN V_DATE = CURRENT_DATE THEN CURRENT_TIMESTAMP +ELSE +TO_DATE ( +ZONED ( V_DATE ) || '235959' , 'YYYYMMDDHH24MISS' ) +END AS DEFAULT_END_TS +FROM SYSIBM . SYSDUMMY1 +) , +RUN_MATCHED AS ( +SELECT ON_T . ORDNO , ON_T . ITNBR , ON_T . WKCTR , ON_T . STID , +ON_T . ON_TS AS START_TS , +COALESCE ( OFF_T . OFF_TS , CE . DEFAULT_END_TS ) AS END_TS , +COALESCE ( OFF_T . OFF_DATE , V_DATE_CY ) AS OFF_DATE , +COALESCE ( +OFF_T . OFF_TIME , +CASE +WHEN +V_DATE = CURRENT_DATE +THEN ZONED ( CURRENT_TIME ) +ELSE 235959 +END ) AS OFF_TIME , +COALESCE ( OFF_T . QTCOM , 0 ) AS QTY_COMPLETE , +COALESCE ( OFF_T . QTSCP , 0 ) AS QTY_SCRAP , +CASE +COALESCE ( R . TBCDE , ' ' ) +WHEN +' ' +THEN +CASE +WHEN +COALESCE ( R . SRLHU , 0 ) > 0 +THEN 1.0 / R . SRLHU / 60 +ELSE 0 +END +WHEN 'P' THEN COALESCE ( R . SRLHU , 0 ) / 60 +WHEN +'M' +THEN +CASE +WHEN +COALESCE ( R . SRLHU , 0 ) > 0 +THEN 1.0 / R . SRLHU +ELSE 0 +END +WHEN +'1' +THEN +CASE +WHEN +COALESCE ( R . SRLHU , 0 ) > 0 +THEN 10.0 / R . SRLHU / 60 +ELSE 0 +END +WHEN +'2' +THEN +CASE +WHEN +COALESCE ( R . SRLHU , 0 ) > 0 +THEN 100.0 / R . SRLHU / 60 +ELSE 0 +END +WHEN +'3' +THEN +CASE +WHEN +COALESCE ( R . SRLHU , 0 ) > 0 +THEN 1000.0 / R . SRLHU / 60 +ELSE 0 +END +ELSE 0 +END AS PCS_PER_MIN +FROM RUN_ON ON_T +CROSS JOIN CURRENT_END CE +LEFT JOIN RUN_OFF OFF_T +ON ON_T . ORDNO = OFF_T . ORDNO +AND ON_T . OPSEQ = OFF_T . OPSEQ +AND ON_T . EMP_KEY = OFF_T . EMP_KEY +AND ON_T . RUNCD = OFF_T . RUNCD +AND ON_T . SEQ = OFF_T . SEQ +AND ON_T . WKCTR = OFF_T . WKCTR +AND ON_T . STID = OFF_T . STID +LEFT JOIN MOROUT R +ON ON_T . ORDNO = R . ORDNO +AND ON_T . OPSEQ = R . OPSEQ +) , +-- ========== DOWNTIME TRANSACTIONS (DB/DE) ========== +DOWN_BEGIN AS ( +SELECT T . ORDNO , T . OPSEQ , +CAST ( +CAST ( T . RECD AS VARCHAR ( 6 ) CCSID 37 ) AS VARCHAR ( 6 ) +CCSID 1208 ) AS REASON_CODE , T . WKCTR , +COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , +T . TDATE AS DB_DATE , T . TTIME AS DB_TIME , M . STID , +TO_DATE ( +ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || +LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) +AS DB_TS , +ROW_NUMBER ( ) OVER ( +PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( +T . EMPNO , T . BADGE ) , T . WKCTR +ORDER BY T . TDATE , T . TTIME +) AS SEQ +FROM MOTRAN T +JOIN MOMAST M +ON T . ORDNO = M . ORDNO +WHERE T . TCODE = 'DB' +AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) +AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) +AND T . ACREC = 'A' +AND T . TDATE BETWEEN V_DATE_PRIOR_CY AND V_DATE_CY +) , +DOWN_END AS ( +SELECT T . ORDNO , T . OPSEQ , T . WKCTR , +COALESCE ( T . EMPNO , T . BADGE ) AS EMP_KEY , +T . TDATE AS DE_DATE , T . TTIME AS DE_TIME , M . STID , +TO_DATE ( +ZONED ( CISTOOLS . CYMD2DATE ( T . TDATE ) ) || +LPAD ( T . TTIME , 6 , '0' ) , 'YYYYMMDDHH24MISS' ) +AS DE_TS , +ROW_NUMBER ( ) OVER ( +PARTITION BY T . ORDNO , T . OPSEQ , COALESCE ( +T . EMPNO , T . BADGE ) , T . WKCTR +ORDER BY T . TDATE , T . TTIME +) AS SEQ +FROM MOTRAN T +JOIN MOMAST M +ON T . ORDNO = M . ORDNO +WHERE T . TCODE = 'DE' +AND T . WKCTR = COALESCE ( NULLIF ( V_WC , '' ) , T . WKCTR ) +AND M . STID = COALESCE ( NULLIF ( V_SITE , '' ) , M . STID ) +AND T . ACREC = 'A' +AND T . TDATE = V_DATE_CY +) , +DOWN_MATCHED AS ( +SELECT DB . ORDNO , DB . REASON_CODE , DB . WKCTR , DB . STID , +COALESCE ( R . KDSCHED , 'N' ) AS IS_SCHEDULED , +DB . DB_TS AS START_TS , +COALESCE ( DE . DE_TS , CE . DEFAULT_END_TS ) AS END_TS +FROM DOWN_BEGIN DB +CROSS JOIN CURRENT_END CE +LEFT JOIN DOWN_END DE +ON DB . ORDNO = DE . ORDNO +AND DB . OPSEQ = DE . OPSEQ +AND DB . EMP_KEY = DE . EMP_KEY +AND DB . SEQ = DE . SEQ +AND DB . WKCTR = DE . WKCTR +AND DB . STID = DE . STID +LEFT JOIN SFCDWR R +ON DB . REASON_CODE = R . KDREASN +) , +-- ========== WORKCENTER/SITE LIST ========== +WC_SITE_LIST AS ( +SELECT DISTINCT WKCTR , STID +FROM RUN_MATCHED +UNION +SELECT DISTINCT WKCTR , STID +FROM DOWN_MATCHED +) , +-- ========== HOURLY BREAKDOWN ========== +ALL_HOURS AS ( +SELECT HR AS HOUR_NUM , +TO_DATE ( +ZONED ( V_DATE ) || LPAD ( HR * 10000 , 6 , '0' ) , +'YYYYMMDDHH24MISS' ) AS HR_START_TS , +CASE +WHEN +HR = 23 +THEN +TO_DATE ( +ZONED ( V_DATE + 1 DAY ) || '000000' , +'YYYYMMDDHH24MISS' ) +ELSE +TO_DATE ( +ZONED ( V_DATE ) || +LPAD ( ( HR + 1 ) * 10000 , 6 , '0' ) , +'YYYYMMDDHH24MISS' ) +END AS HR_END_TS +FROM ( +VALUES ( 0 ) , ( 1 ) , ( 2 ) , ( 3 ) , ( 4 ) , ( 5 ) , ( 6 ) , ( 7 ) , ( 8 ) ,( 9 ) , ( 10 ) , ( 11 ) , ( 12 ) , ( 13 ) , ( 14 ) , ( 15 ) , +( 16 ) , ( 17 ) , ( 18 ) , ( 19 ) , ( 20 ) , ( 21 ) , ( 22 ) , +( 23 ) +) T ( HR ) +) , +-- Run time by hour per workcenter/site +RUN_HOURLY AS ( +SELECT H . HOUR_NUM , R . WKCTR , R . STID , +GREATEST ( +0 , TIMESTAMPDIFF ( +2 , CHAR ( +LEAST ( R . END_TS , H . HR_END_TS ) - +GREATEST ( R . START_TS , H . HR_START_TS ) ) ) ) +AS RUN_SECONDS , R . PCS_PER_MIN , R . QTY_COMPLETE , +R . QTY_SCRAP , R . OFF_DATE , R . OFF_TIME , R . ITNBR , R . ORDNO +FROM RUN_MATCHED R , ALL_HOURS H +WHERE R . START_TS < H . HR_END_TS +AND R . END_TS > H . HR_START_TS +) , +RUN_BY_HOUR AS ( +SELECT HOUR_NUM , WKCTR , STID , SUM ( RUN_SECONDS ) AS RUN_SEC , +DEC ( +SUM ( +DEC ( RUN_SECONDS , 15 , 4 ) * +DEC ( PCS_PER_MIN , 15 , 8 ) / 60 ) , 15 , 4 ) +AS EXPECTED_QTY , +SUM ( +CASE +WHEN +HOUR ( +TO_DATE ( +ZONED ( CISTOOLS . CYMD2DATE ( OFF_DATE ) ) || +LPAD ( OFF_TIME , 6 , '0' ) , +'YYYYMMDDHH24MISS' ) ) = HOUR_NUM +AND CISTOOLS . CYMD2DATE ( OFF_DATE ) = V_DATE +THEN QTY_COMPLETE +ELSE 0 +END ) AS ACTUAL_QTY , +SUM ( +CASE +WHEN +HOUR ( +TO_DATE ( +ZONED ( CISTOOLS . CYMD2DATE ( OFF_DATE ) ) || +LPAD ( OFF_TIME , 6 , '0' ) , +'YYYYMMDDHH24MISS' ) ) = HOUR_NUM +AND CISTOOLS . CYMD2DATE ( OFF_DATE ) = V_DATE +THEN QTY_SCRAP +ELSE 0 +END ) AS SCRAP_QTY +FROM RUN_HOURLY +WHERE RUN_SECONDS > 0 +GROUP BY HOUR_NUM , WKCTR , STID +) , +-- Items per hour/wkctr/stid +HOURLY_ITEMS AS ( +SELECT DISTINCT HOUR_NUM , WKCTR , STID , ORDNO , ITNBR +FROM RUN_HOURLY +WHERE RUN_SECONDS > 0 +) , +HOURLY_ITEMS_AGG AS ( +SELECT HOUR_NUM , WKCTR , STID , +JSON_ARRAYAGG ( +JSON_OBJECT ( +'orderNumber' : CAST ( +CAST ( TRIM ( ORDNO ) AS VARCHAR ( 15 ) CCSID 37 ) AS +VARCHAR ( 15 ) CCSID 1208 ) , 'itemNumber' : CAST ( +CAST ( TRIM ( ITNBR ) AS VARCHAR ( 15 ) CCSID 37 ) AS +VARCHAR ( 15 ) CCSID 1208 ) +) FORMAT JSON +) AS ITEMS +FROM HOURLY_ITEMS +GROUP BY HOUR_NUM , WKCTR , STID +) , +-- Downtime by hour per workcenter/site +DOWN_HOURLY AS ( +SELECT H . HOUR_NUM , D . WKCTR , D . STID , D . IS_SCHEDULED , +GREATEST ( +0 , TIMESTAMPDIFF ( +2 , CHAR ( +LEAST ( D . END_TS , H . HR_END_TS ) - +GREATEST ( D . START_TS , H . HR_START_TS ) ) ) ) +AS DOWN_SECONDS +FROM DOWN_MATCHED D , ALL_HOURS H +WHERE D . START_TS < H . HR_END_TS +AND D . END_TS > H . HR_START_TS +) , +DOWN_BY_HOUR AS ( +SELECT HOUR_NUM , WKCTR , STID , SUM ( +CASE +WHEN IS_SCHEDULED = 'Y' THEN DOWN_SECONDS +ELSE 0 +END ) AS SCHED_DOWN_SEC , SUM ( +CASE +WHEN IS_SCHEDULED <> 'Y' THEN DOWN_SECONDS +ELSE 0 +END ) AS UNSCHED_DOWN_SEC +FROM DOWN_HOURLY +WHERE DOWN_SECONDS > 0 +GROUP BY HOUR_NUM , WKCTR , STID +) , +-- ========== COMBINE AND CALCULATE OEE ========== +HOURLY_COMBINED AS ( +SELECT A . HOUR_NUM , W . WKCTR , W . STID , +COALESCE ( R . RUN_SEC , 0 ) AS RUN_SEC , +COALESCE ( R . EXPECTED_QTY , DEC ( 0 , 15 , 4 ) ) +AS EXPECTED_QTY , +COALESCE ( R . ACTUAL_QTY , DEC ( 0 , 15 , 4 ) ) AS ACTUAL_QTY , +COALESCE ( R . SCRAP_QTY , DEC ( 0 , 15 , 4 ) ) AS SCRAP_QTY , +COALESCE ( D . SCHED_DOWN_SEC , 0 ) AS SCHED_DOWN_SEC , +COALESCE ( D . UNSCHED_DOWN_SEC , 0 ) AS UNSCHED_DOWN_SEC , +I . ITEMS , +LEAST ( +COALESCE ( R . RUN_SEC , 0 ) + +COALESCE ( D . SCHED_DOWN_SEC , 0 ) + +COALESCE ( D . UNSCHED_DOWN_SEC , 0 ) , 3600 ) +AS TOTAL_ACTIVE_SEC +FROM ALL_HOURS A +CROSS JOIN WC_SITE_LIST W +LEFT JOIN RUN_BY_HOUR R +ON A . HOUR_NUM = R . HOUR_NUM +AND W . WKCTR = R . WKCTR +AND W . STID = R . STID +LEFT JOIN DOWN_BY_HOUR D +ON A . HOUR_NUM = D . HOUR_NUM +AND W . WKCTR = D . WKCTR +AND W . STID = D . STID +LEFT JOIN HOURLY_ITEMS_AGG I +ON A . HOUR_NUM = I . HOUR_NUM +AND W . WKCTR = I . WKCTR +AND W . STID = I . STID +) , +HOURLY_WITH_CUM AS ( +SELECT H . * , SUM ( RUN_SEC ) OVER ( +PARTITION BY WKCTR , STID +ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING +) AS CUM_RUN , SUM ( EXPECTED_QTY ) OVER ( +PARTITION BY WKCTR , STID +ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING +) AS CUM_EXPECTED , SUM ( ACTUAL_QTY ) OVER ( +PARTITION BY WKCTR , STID +ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING +) AS CUM_ACTUAL , SUM ( SCRAP_QTY ) OVER ( +PARTITION BY WKCTR , STID +ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING +) AS CUM_SCRAP , SUM ( SCHED_DOWN_SEC ) OVER ( +PARTITION BY WKCTR , STID +ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING +) AS CUM_SCHED_DOWN , SUM ( UNSCHED_DOWN_SEC ) OVER ( +PARTITION BY WKCTR , STID +ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING +) AS CUM_UNSCHED_DOWN , SUM ( TOTAL_ACTIVE_SEC ) OVER ( +PARTITION BY WKCTR , STID +ORDER BY HOUR_NUM ROWS UNBOUNDED PRECEDING +) AS CUM_ACTIVE +FROM HOURLY_COMBINED H +) , +HOURLY_OEE AS ( +SELECT H . * , +CASE +WHEN +TOTAL_ACTIVE_SEC > 0 +THEN +INT ( +( CAST ( RUN_SEC AS DOUBLE ) / +CAST ( TOTAL_ACTIVE_SEC AS DOUBLE ) ) * 100 ++ 0.5 ) +ELSE 0 +END AS HRLY_AVAIL , +CASE +WHEN +EXPECTED_QTY > 0 +THEN +LEAST ( +INT ( +( ACTUAL_QTY / EXPECTED_QTY ) * 100 + +0.5 ) , 999 ) +ELSE 0 +END AS HRLY_PERF , +CASE +WHEN +( ACTUAL_QTY + SCRAP_QTY ) > 0 +THEN +INT ( +( ACTUAL_QTY / ( ACTUAL_QTY + SCRAP_QTY ) ) * +100 + 0.5 ) +ELSE 100 +END AS HRLY_QUAL , +CASE +WHEN +CUM_ACTIVE > 0 +THEN +INT ( +( CAST ( CUM_RUN AS DOUBLE ) / +CAST ( CUM_ACTIVE AS DOUBLE ) ) * 100 + +0.5 ) +ELSE 0 +END AS CUM_AVAIL , +CASE +WHEN +CUM_EXPECTED > 0 +THEN +LEAST ( +INT ( +( CUM_ACTUAL / CUM_EXPECTED ) * 100 + +0.5 ) , 999 ) +ELSE 0 +END AS CUM_PERF , +CASE +WHEN +( CUM_ACTUAL + CUM_SCRAP ) > 0 +THEN +INT ( +( CUM_ACTUAL / ( CUM_ACTUAL + CUM_SCRAP ) ) * +100 + 0.5 ) +ELSE 100 +END AS CUM_QUAL +FROM HOURLY_WITH_CUM H +) , +HOURLY_FINAL AS ( +SELECT H . * , +CASE +WHEN +HRLY_AVAIL > 0 +AND HRLY_PERF > 0 +AND HRLY_QUAL > 0 +THEN +INT ( +( CAST ( HRLY_AVAIL AS DOUBLE ) * +CAST ( HRLY_PERF AS DOUBLE ) * +CAST ( HRLY_QUAL AS DOUBLE ) / 10000 ) + +0.5 ) +ELSE 0 +END AS HRLY_OEE , +CASE +WHEN +CUM_AVAIL > 0 +AND CUM_PERF > 0 +AND CUM_QUAL > 0 +THEN +INT ( +( CAST ( CUM_AVAIL AS DOUBLE ) * +CAST ( CUM_PERF AS DOUBLE ) * +CAST ( CUM_QUAL AS DOUBLE ) / 10000 ) + +0.5 ) +ELSE 0 +END AS CUM_OEE +FROM HOURLY_OEE H +) , +-- ========== SHIFT TIMES PER WORKCENTER ========== +SHIFT_TIMES AS ( +SELECT W . WSWKCT AS WKCTR , W . WSSTID AS STID , +W . WSSF1B AS SHIFT1_BEGIN , W . WSSF1E AS SHIFT1_END , +W . WSSF2B AS SHIFT2_BEGIN , W . WSSF2E AS SHIFT2_END , +W . WSSF3B AS SHIFT3_BEGIN , W . WSSF3E AS SHIFT3_END , +W . WSDEND AS DAY_END +FROM SFCCWKS W +) , +-- ========== BUILD JSON ========== +JSON_HOURS AS ( +SELECT WKCTR , STID , HOUR_NUM , +JSON_OBJECT ( +'hour' : HOUR_NUM , 'hourLabel' : +CASE +WHEN HOUR_NUM = 0 THEN '12AM' +WHEN +HOUR_NUM < 12 +THEN TRIM ( CHAR ( HOUR_NUM ) ) || 'AM' +WHEN HOUR_NUM = 12 THEN '12PM' +ELSE TRIM ( CHAR ( HOUR_NUM - 12 ) ) || 'PM' +END , +'items' : COALESCE ( ITEMS , JSON_ARRAY ( ) ) FORMAT JSON , +'runMinutes' : INT ( RUN_SEC / 60 ) , +'scheduledDownMinutes' : INT ( SCHED_DOWN_SEC / 60 ) , +'unscheduledDownMinutes' : INT ( +UNSCHED_DOWN_SEC / 60 ) , 'expectedQty' : DEC ( +EXPECTED_QTY , 10 , 2 ) , 'actualQty' : DEC ( +ACTUAL_QTY , 10 , 2 ) , 'scrapQty' : DEC ( +SCRAP_QTY , 10 , 2 ) , 'cumulativeExpected' : DEC ( +CUM_EXPECTED , 10 , 2 ) , 'cumulativeActual' : DEC ( +CUM_ACTUAL , 10 , 2 ) , 'cumulativeScrap' : DEC ( +CUM_SCRAP , 10 , 2 ) , 'variance' : DEC ( +CUM_ACTUAL - CUM_EXPECTED , 10 , 2 ) , +'hourlyAvailability' : HRLY_AVAIL , +'hourlyPerformance' : HRLY_PERF , +'hourlyQuality' : HRLY_QUAL , 'hourlyOee' : HRLY_OEE , +'cumulativeAvailability' : CUM_AVAIL , +'cumulativePerformance' : CUM_PERF , +'cumulativeQuality' : CUM_QUAL , +'cumulativeOee' : CUM_OEE +) AS HOUR_OBJ +FROM HOURLY_FINAL +) , +WC_TOTALS AS ( +SELECT WKCTR , STID , MAX ( CUM_ACTUAL ) AS TOTAL_ACTUAL , +MAX ( CUM_EXPECTED ) AS TOTAL_EXPECTED , +MAX ( CUM_SCRAP ) AS TOTAL_SCRAP , +MAX ( CUM_RUN ) AS TOTAL_RUN_SEC , +MAX ( CUM_SCHED_DOWN ) AS TOTAL_SCHED_DOWN , +MAX ( CUM_UNSCHED_DOWN ) AS TOTAL_UNSCHED_DOWN , +MAX ( CUM_OEE ) AS FINAL_OEE , +MAX ( CUM_AVAIL ) AS FINAL_AVAIL , +MAX ( CUM_PERF ) AS FINAL_PERF , +MAX ( CUM_QUAL ) AS FINAL_QUAL +FROM HOURLY_FINAL +GROUP BY WKCTR , STID +) , +JSON_WORKCENTERS AS ( +SELECT +JSON_OBJECT ( +'workcenter' : CAST ( +CAST ( T . WKCTR AS VARCHAR ( 5 ) CCSID 37 ) AS VARCHAR ( +5 ) CCSID 1208 ) , 'site' : CAST ( +CAST ( T . STID AS VARCHAR ( 3 ) CCSID 37 ) AS VARCHAR ( 3 ) +CCSID 1208 ) , 'hours' : ( SELECT JSON_ARRAYAGG ( +H . HOUR_OBJ FORMAT JSON +ORDER BY H . HOUR_NUM +) +FROM JSON_HOURS H +WHERE H . WKCTR = T . WKCTR +AND H . STID = T . STID ) FORMAT JSON , +'totals' : JSON_OBJECT ( +'actualQty' : DEC ( +COALESCE ( T . TOTAL_ACTUAL , DEC ( 0 , 15 , 4 ) ) , 10 , +2 ) , 'expectedQty' : DEC ( +COALESCE ( T . TOTAL_EXPECTED , DEC ( 0 , 15 , 4 ) ) , 10 , +2 ) , +'scrapQty' : DEC ( +COALESCE ( T . TOTAL_SCRAP , DEC ( 0 , 15 , 4 ) ) , 10 , 2 +) , 'variance' : DEC ( +COALESCE ( +T . TOTAL_ACTUAL - T . TOTAL_EXPECTED , DEC ( +0 , 15 , 4 ) ) , 10 , 2 ) , 'runMinutes' : INT ( +COALESCE ( T . TOTAL_RUN_SEC , 0 ) / 60 ) , +'scheduledDownMinutes' : INT ( +COALESCE ( T . TOTAL_SCHED_DOWN , 0 ) / 60 ) , +'unscheduledDownMinutes' : INT ( +COALESCE ( T . TOTAL_UNSCHED_DOWN , 0 ) / 60 ) , +'oeePercentage' : COALESCE ( T . FINAL_OEE , 0 ) , +'availabilityPercentage' : COALESCE ( +T . FINAL_AVAIL , 0 ) , +'performancePercentage' : COALESCE ( +T . FINAL_PERF , 0 ) , +'qualityPercentage' : COALESCE ( T . FINAL_QUAL , 0 ) +) , 'shiftTimes' : ( +SELECT JSON_OBJECT ( +'shift1Begin' : +CASE +WHEN +S . SHIFT1_BEGIN > 0 +THEN +SUBSTRING ( +LPAD ( S . SHIFT1_BEGIN , 6 , '0' ) , +1 , 2 ) || ':' || +SUBSTRING ( +LPAD ( +S . SHIFT1_BEGIN , 6 , '0' ) , +3 , 2 ) +ELSE NULL +END , 'shift1End' : +CASE +WHEN +S . SHIFT1_END > 0 +THEN +SUBSTRING ( +LPAD ( S . SHIFT1_END , 6 , '0' ) , 1 , +2 ) || ':' || +SUBSTRING ( +LPAD ( S . SHIFT1_END , 6 , '0' ) , +3 , 2 ) +ELSE NULL +END , 'shift2Begin' : +CASE +WHEN +S . SHIFT2_BEGIN > 0 +THEN +SUBSTRING ( +LPAD ( S . SHIFT2_BEGIN , 6 , '0' ) , +1 , 2 ) || ':' || +SUBSTRING ( +LPAD ( +S . SHIFT2_BEGIN , 6 , '0' ) , +3 , 2 ) +ELSE NULL +END , 'shift2End' : +CASE +WHEN +S . SHIFT2_END > 0 +THEN +SUBSTRING ( +LPAD ( S . SHIFT2_END , 6 , '0' ) , 1 , +2 ) || ':' || +SUBSTRING ( +LPAD ( S . SHIFT2_END , 6 , '0' ) , +3 , 2 ) +ELSE NULL +END , 'shift3Begin' : +CASE +WHEN +S . SHIFT3_BEGIN > 0 +THEN +SUBSTRING ( +LPAD ( S . SHIFT3_BEGIN , 6 , '0' ) , +1 , 2 ) || ':' || +SUBSTRING ( +LPAD ( +S . SHIFT3_BEGIN , 6 , '0' ) , +3 , 2 ) +ELSE NULL +END , 'shift3End' : +CASE +WHEN +S . SHIFT3_END > 0 +THEN +SUBSTRING ( +LPAD ( S . SHIFT3_END , 6 , '0' ) , 1 , +2 ) || ':' || +SUBSTRING ( +LPAD ( S . SHIFT3_END , 6 , '0' ) , +3 , 2 ) +ELSE NULL +END , 'dayEnd' : +CASE +WHEN +S . DAY_END > 0 +THEN +SUBSTRING ( +LPAD ( S . DAY_END , 6 , '0' ) , 1 , 2 ) +|| ':' || +SUBSTRING ( +LPAD ( S . DAY_END , 6 , '0' ) , 3 , +2 ) +ELSE NULL +END +) +FROM SHIFT_TIMES S +WHERE S . WKCTR = T . WKCTR +AND S . STID = T . STID +FETCH FIRST 1 ROW ONLY ) FORMAT JSON +) AS WC_OBJ +FROM WC_TOTALS T +ORDER BY T . WKCTR , T . STID ) SELECT JSON_ARRAY ( +JSON_OBJECT ( +'date' : TO_CHAR ( V_DATE , 'YYYY-MM-DD' ) , 'workcenters' : ( +SELECT JSON_ARRAYAGG ( +WC_OBJ FORMAT JSON +) +FROM JSON_WORKCENTERS ) FORMAT JSON , +'dataSource' : 'MOTRAN (Live)' , 'generatedAt' : TO_CHAR ( +CURRENT_TIMESTAMP , 'YYYY-MM-DD HH24:MI:SS' ) +) ) +FROM SYSIBM . SYSDUMMY1 ; +END ; + +GRANT ALTER , EXECUTE +ON SPECIFIC FUNCTION RESTAPI.SFP_GET_HOURLY_OEE +TO AMAPICS WITH GRANT OPTION ; + +GRANT EXECUTE +ON SPECIFIC FUNCTION RESTAPI.SFP_GET_HOURLY_OEE +TO PUBLIC ; +