Standards for Custom Reports with SAP SuccessFactors Learning Report Designer TABLE OF CONTENTS HANDLING DATES AND DATETIME CONVERSIONS............................................................................................. 4 Time Zone Conversion Without Handler Class ................................................................................................ 4 SCRIPT GUIDELINES ................................................................................................................................................... 5 Exporting the Standard Report to Import as Custom Report ........................................................................ 5 Do Not Write Queries that Result in Out of Memory ....................................................................................... 5 Use Column Names in Place of * for Select clause ......................................................................................... 5 Do Not Use Count(*), count(distinct (select ... ................................................................................................ 6 Use Different Alias Names for Tables ................................................................................................................ 8 Add Table Alias Names to Columns Used in JOIN Conditions ...................................................................... 8 Do Not Use WITH Clause inside FROM and JOIN Condition............................................................................. 9 Handling Connect by Queries - Example 1: .................................................................................................... 10 Handling Connect by Queries - Example 2: .................................................................................................... 12 Do Not Use LISTAGG ............................................................................................................................................ 12 Do Not Use DBMS_LOB .......................................................................................................................................... 13 Do Not Use Inner Keyword .............................................................................................................................. 13 Do Not Use WM_CONCAT ........................................................................................................................................ 13 Do Not Use UNIQUE keyword .............................................................................................................................. 13 Do Not Use LOCATION Keyword as Alias .......................................................................................................... 14 Do Not Use INSTR2 .............................................................................................................................................. 14 Do Not Put Spaces in Logical Operators......................................................................................................... 14 Do Not Use Parentheses for Group By Clauses with Multiple Columns.................................................... 14 Do Not Select All Columns................................................................................................................................. 14 Use NVARCHAR Instead of varchar2 in Cast Functions .................................................................................. 15 Aliases with Special Characters ....................................................................................................................... 15 Do Not Use Columns Names with Table Names ............................................................................................ 15 Use Consistent Data Types between DB Column Type and Report Designer Column Type ................ 15 Do Not Use Case Statements with Mixed Datatypes..................................................................................... 15 Using Keywords LIMIT and CURRENT_DATE as Aliases .................................................................................. 16 Column Names in rptdesign file ....................................................................................................................... 16 Do Not Use '&' in Column Alias......................................................................................................................... 16 Do Not Use Group By with Multiple Columns Inside Parentheses ............................................................. 16 Using milliseconds functions............................................................................................................................ 16 Do Not Use CAST_TO_RAW in UTL_RAW .............................................................................................................. 17 Using Federal Customers Functions ............................................................................................................... 17 Using pkg_student.get_delm_stud_qual_stat_rmday .................................................................................. 17 Using Functions that Occur in Select .............................................................................................................. 17 Using Functions that Occur in a Where Clause ............................................................................................. 18 Parameters in the Function ............................................................................................................................... 18 2 Using a Function Wrapped with a System Function ..................................................................................... 19 Using Functions Above Multiple Unions ......................................................................................................... 20 System Tables ...................................................................................................................................................... 20 Using a Column Alias ......................................................................................................................................... 21 Using a Table Alias.............................................................................................................................................. 21 Using a Column Alias with an Apostrophe ..................................................................................................... 21 Using a Numeric Function with SUBSTR ........................................................................................................ 21 Queries that Result in Out of Memory – Example 1: ..................................................................................... 21 Queries that Result in Out of Memory – Example 2: ..................................................................................... 22 3 We continue to optimize the performance and utilization of the SAP SuccessFactors Learning Report Designer. As such, ANSI SQL is our mandatory standard for SAP SuccessFactors Learning Report Designer. When you write report SQL in ANSI SQL, we have a higher confidence that those reports will deliver accurate and consistent results. Dates and datetime conversions may require changes in your reports. Please review guidance below on handling dates and datetime conversion. HANDLING DATES AND DATETIME CONVERSIONS Time zone conversion can be difficult when you write a custom report in Learning. In general, please follow this standard: start with UTC and convert the date-times into the correct time zone for the user. This applies to datetime fields: · Date-time fields (as opposed to date fields) appear to report readers in UTC by default. - If you apply explicit BIRT time zone conversion to a date-time field, the report honors the conversion: readers of the reports see the date-time converted. - Do not for example, assume that you can rely on the time zone of the data center. Instead, assume that the raw date-time is in UTC. · Date fields (as opposed to date-time fields) should not have a time zone conversion - For example, assignment date is a date field, so it does not require time zone conversion. - Do not use the BIRT operator for time zone conversion on date fields because time zones make sense for date-time fields only. Time Zone Conversion Without Handler Class You can use the following function to convert from UTC to your preferred time zone: pkg_tool_get_new_date(column, 'UTC' ,'America/New_York') alias column - The column name you want to convert (This must be date time field only) UTC - The current time zone, which always remains the same America/New_York - The target time zone you want to convert to alias - The alias you want to give to your column Example: SELECT STUD_ID, CPNT_ID, pkg_tool_get_new_date(COMPL_DTE, 'UTC', 'America/New_York') COMPL_DTE FROM pa_cbt_stud_cpnt; Note: The target time zone should be from the list of time zones available in the system. This time zone can be checked from the Learning Admin Application. Log in as an Admin and navigate to References > Calendars & Time > Timezone Management 4 SCRIPT GUIDELINES Follow these guidelines when writing SQL script for custom reports. Exporting the Standard Report to Import as Custom Report You may use a standard report and modify it for your own customized use. If your reports were updated, please remember to export and then make changes. Modified reports are your responsibility going forward. To export the standard report and import it as a custom report, you need to replace the following statement: var hanaDBDialectEnabled = session.getAttribute("HanaDBDialectEnabled"); to var hanaDBDialectEnabled = session.getAttribute("CustomReportHanaDBDialectEnabled Example: <method name="beforeFactory"><![CDATA[ importPackage(Packages.com.plateausystems.elms.framework.report.impl) importPackage(Packages.javax.servlet.http) importPackage(Packages.javax.servlet) var reportContext1 = reportContext.getAppContext().get("REPORT_CONTEXT"); var session = reportContext1.session; var hanaDBDialectEnabled = session.getAttribute("CustomReportHanaDBDialectEnabled"); if( hanaDBDialectEnabled ){ ds = reportContext.getReportRunnable().designHandle.getDesignHandle().findElement("Learning_Table") ds.setProperty( "dataSet", "DataSet_Hana" ); }else{ ds = reportContext.getReportRunnable().designHandle.getDesignHandle().findElement("Learning_Table") ds.setProperty( "dataSet", "DataSet" ); Do Not Write Queries that Result in Out of Memory Do not use projection SELECT statements within a projection SELECT statement. Instead use a JOIN (FROM Clause) or a WITH clause. Use Column Names in Place of * for Select clause Previous Script select * from pa_cpnt_doc 5 Standard Script select CPNT_ID, CPNT_TYP_ID, REV_DTE, DOC_ID, REVIEW_FLG, LST_UPD_USR, LST_UPD_TSTMP from pa_cpnt_doc Do Not Use Count(*), count(distinct (select ... Previous Script select * from ( select (row_number() over()) row_num, cpnt_typ_id, record_num, course_num, session_num, manday from ( select coalesce(evt.cpnt_typ_id, 'Grand Total') cpnt_typ_id, count(*) record_num, count(distinct IFNULL(to_char(evt.cpnt_typ_id), '') || IFNULL(to_char(evt.cpnt_id), '')) course_num, count(distinct (select schd_id from pa_sched where schd_id = evt.schd_id and cancelled <> 'Y' and (closed_date is null OR LENGTH( closed_date) = 0 ))) session_num, round(sum(to_number(coalesce(evt.cpe_hrs, 0) + coalesce(evt.credit_hrs, 0) + coalesce(evt.contact_hrs, 0)))/6, 2) manday from pa_cpnt_evthst evt join pa_student stud on stud.stud_id = evt.stud_id join pa_cpnt cpnt on cpnt.cpnt_typ_id = evt.cpnt_typ_id and cpnt.cpnt_id = evt.cpnt_id and cpnt.rev_dte = evt.rev_dte where lower(evt.cmpl_stat_id) like '%_complete%' and (coalesce(evt.cpe_hrs, 0) + coalesce(evt.credit_hrs, 6 0) + coalesce(evt.contact_hrs, 0)) > 0 and evt.compl_dte >= ? and not (PKG_SQL_SUBTRACT_SECONDS ( evt.compl_dte, 86399 ) ) > ? group by rollup(evt.cpnt_typ_id) order by lower(evt.cpnt_typ_id) NULLS LAST ) ) Standard Script select * from ( select (row_number() over()) row_num, cmpty_skill, record_num, course_num, session_num, manday from ( select coalesce(cpnt.cmpty_skill, 'Grand Total') cmpty_skill, count(distinct IFNULL(to_char(evt.cpnt_typ_id), '') || IFNULL(to_char(evt.cpnt_id), '')) course_num, count(distinct (select schd_id from pa_sched where schd_id = evt.schd_id and (closed_date is null OR LENGTH( closed_date) = 0 ) and cancelled <> 'Y')) session_num, count(*) record_num, round(sum(to_number(coalesce(evt.cpe_hrs, 0) + coalesce(evt.credit_hrs, 0) + coalesce(evt.contact_hrs, 0)))/6, 2) manday from pa_cpnt_evthst evt join (select cp.cpnt_typ_id, cp.cpnt_id, cp.rev_dte, cpus.user_value cmpty_skill from pa_cpnt cp left join pa_cpnt_user cpus on cpus.cpnt_typ_id = cp.cpnt_typ_id and cpus.cpnt_id = cp.cpnt_id and cpus.rev_dte = cp.rev_dte where cpus.col_num = '10' ) cpnt on cpnt.cpnt_typ_id = evt.cpnt_typ_id and cpnt.cpnt_id = evt.cpnt_id and cpnt.rev_dte = evt.rev_dte left join pa_sched sch on sch.schd_id = evt.schd_id join pa_student stud on stud.stud_id = evt.stud_id 7 0) + 0) + 0) > 86399 where (cpnt.cmpty_skill is not null AND LENGTH( cpnt.cmpty_skill) != 0 ) and lower(evt.cmpl_stat_id) like '%_complete%' and ( coalesce(evt.cpe_hrs, coalesce(evt.credit_hrs, coalesce(evt.contact_hrs, 0 ) and evt.compl_dte >= ? and not (PKG_SQL_SUBTRACT_SECONDS ( evt.compl_dte, ) ) > ? group by rollup(cpnt.cmpty_skill) order by cpnt.cmpty_skill NULLS LAST ) ) Use Different Alias Names for Tables Do not use the same table alias name for more than one table. Previous Script SELECT DISTINCT c.cpnt_typ_id, c.cpnt_id, c.rev_dte , cs.cpnt_src_desc, from pa_cpnt, pa_cpnt_src cs, pa_cpnt_subj cs, pa_cpnt_formula cf where cf.cpnt_typ_id (+) = c.cpnt_typ_id and cs.cpnt_id(+) = c.cpnt_id Standard Script SELECT DISTINCT c.cpnt_typ_id, c.cpnt_id, c.rev_dte , cs.cpnt_src_desc, from pa_cpnt, pa_cpnt_src cs, pa_cpnt_subj cs , pa_cpnt_formula cf where c.cpnt_typ_id = cf.cpnt_typ_id (+) and c.cpnt_id = cs.cpnt_id(+) Add Table Alias Names to Columns Used in JOIN Conditions Add a table name alias to a column used in join condition. Column names without an alias are not added in the join clause condition. Previous Script Select pr.FORMULA, 8 pr.CURRENCY_CODE From PA_CPNT_FORMULA pr Where IS_DEFAULT (+) = 'Y' and fin_var_id (+) = 'ItemDefaultPublishedPrice' Standard Script Select pr.FORMULA, pr.CURRENCY_CODE From PA_CPNT_FORMULA pr Where pr.IS_DEFAULT (+) = 'Y' and pr.fin_var_id (+) = 'ItemDefaultPublishedPrice' Do Not Use WITH Clause inside FROM and JOIN Condition Use a SELECT statement in place of a WITH clause when you are inside a FROM and JOIN condition. Use WHERE to add additional SELECT statements. Previous Script SELECT * FROM (SELECT * FROM (WITH summary AS (SELECT sct.*,ROW_NUMBER() OVER(PARTITION BY sct.sc_stud_id_not_used,sct.CPNT_ID,sct.REV_DTE ORDER BY sct.req_dte,sct.assgn_dte ASC) AS rk FROM (SELECT NULL as compl_dte, NULL as cmpl_stat_id, NULL as cmpl_stat_desc,sc.cpnt_typ_id, sc.cpnt_id, sc.rev_dte, sc.rtyp_id, sc.stud_id AS sc_stud_id_not_used, sc.assgn_dte, sc.req_dte, sc.exp_dte FROM pa_stud_qual_cpnt sc WHERE (sc.compl_dte IS NULL OR sc.exp_dte < CURRENT_DATE OR sc.retrng_int > 0) )sct) SELECT s.* FROM summary s WHERE s.rk=1) ) Standard Script SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT sct.*,ROW_NUMBER() OVER(PARTITION BY sct.sc_stud_id_not_used,sct.CPNT_ID,sct.REV_DTE ORDER BY sct.req_dte,sct.assgn_dte ASC) AS rk 9 FROM (SELECT NULL as compl_dte, NULL as cmpl_stat_id, NULL as cmpl_stat_desc, sc.cpnt_typ_id, sc.cpnt_id, sc.rev_dte, sc.rtyp_id, sc.stud_id AS sc_stud_id_not_used, sc.assgn_dte, sc.req_dte, sc.exp_dte FROM pa_stud_qual_cpnt sc WHERE (sc.compl_dte IS NULL OR sc.exp_dte < CURRENT_DATE OR sc.retrng_int > 0) UNION SELECT NULL as compl_dte, NULL as cmpl_stat_id, NULL as cmpl_stat_desc, sc.cpnt_typ_id, sc.cpnt_id, sc.rev_dte, sc.rtyp_id, sc.stud_id AS sc_stud_id_not_used, sc.assgn_dte, sc.req_dte, NULL AS exp_dte FROM PV_STUD_COURSE sc WHERE sc.compl_dte IS NULL )sct) WHERE rk=1 )) Do Not Use Oracle Specific Tuning Statements Examples include: SET ARRAYSIZE SET LINESIZE Handling Connect by Queries - Example 1: Do not use Connect by Prior. Please use H view expressions. Previous Script SELECT 'BOR' as BOR,UPPER(s.STUD_ID) AS eID,LOWER(s.EMAIL_ADDR) AS Email,s.FNAME AS First_Name,s.LNAME AS Last_Name,tEmployee.USER_VALUE AS Employee_Number,tOrg.ORG_DESC AS Department,tJob.JP_DESC AS Title,s.Super,s.JP_ID as Job_Code,us.user_desc as Manager_Level_Desc,su.user_value as Manager_Level_Code,s.dmn_id,s.org_id,tCompany.USER_VALUE AS Company,TO_CHAR(s.Hire_dte, 'YYYY-MMDD') as Hire_Date,s.JL_ID as Job_Location_Id,tLoc.JL_DESC AS Job_Location_Desc,LEVEL,DECODE(s.NOTACTIVE, 'N', 1, 0) as Active FROM PA_STUDENT sLEFT JOIN PA_ORG tOrg on s.ORG_ID = tOrg.ORG_ID LEFT JOIN PA_STUD_USER tEmployee 10 on s.STUD_ID = tEmployee.STUD_IDAND tEmployee.COL_NUM = 1 LEFT JOIN PA_JOB_POS tJob ON s.JP_ID = tJob.JP_ID LEFT JOIN PA_STUDENT tMgr On s.SUPER = tMgr.STUD_ID LEFT JOIN PA_STUD_USER su ON s.STUD_ID = su.STUD_IDAND su.col_num = 2 LEFT JOIN PA_USRRF_STUD us ON su.user_value = us.user_idand us.col_num = 2 LEFT JOIN PA_STUD_USER tCompany on s.STUD_ID = tCompany.STUD_IDAND tCompany.COL_NUM = 4 LEFT JOIN PA_JOB_LOC tLoc ON s.JL_ID = tLoc.JL_ID WHERE s.SUPER != 'PLATEAU' -- AND s.EMAIL_ADDR is not null-- AND s.NOTACTIVE = 'N'AND LOWER(s.EMAIL_ADDR) NOT IN ('conversion@invalid.com', 'invalid@sap.com')/**and [security:PA_STUDENT s]/START WITH UPPER(s.STUD_ID) = 'OJG777'CONNECT BY PRIOR UPPER(s.STUD_ID) = UPPER(s.SUPER)ORDER SIBLINGS BY s.LNAME Standard Script SELECT 'BOR' as BOR, UPPER(s.STUD_ID) AS eID, LOWER(s.EMAIL_ADDR) AS Email, s.FNAME AS First_Name, s.LNAME AS Last_Name, tEmployee.USER_VALUE AS Employee_Number, tOrg.ORG_DESC AS Department, tJob.JP_DESC AS Title, s.Super, s.JP_ID as Job_Code, us.user_desc as Manager_Level_Desc, su.user_value as Manager_Level_Code, s.dmn_id, s.org_id, tCompany.USER_VALUE AS Company, TO_CHAR(s.Hire_dte, 'YYYY-MM-DD') as Hire_Date, s.JL_ID as Job_Location_Id, tLoc.JL_DESC AS Job_Location_Desc, LEVEL, MAP(s.NOTACTIVE, 'N', 1, 0) as Active FROM PA_STUDENT s LEFT JOIN PA_ORG tOrg on s.ORG_ID = tOrg.ORG_ID LEFT JOIN PA_STUD_USER tEmployee on s.STUD_ID = tEmployee.STUD_ID AND tEmployee.COL_NUM = 1 LEFT JOIN PA_JOB_POS tJob ON s.JP_ID = tJob.JP_ID LEFT JOIN PA_STUDENT tMgr On s.SUPER = tMgr.STUD_ID LEFT JOIN PA_STUD_USER su ON s.STUD_ID = su.STUD_ID AND su.col_num = 2 LEFT JOIN PA_USRRF_STUD us 11 ON su.user_value = us.user_id and us.col_num = 2 LEFT JOIN PA_STUD_USER tCompany on s.STUD_ID = tCompany.STUD_ID AND tCompany.COL_NUM = 4 LEFT JOIN PA_JOB_LOC tLoc ON s.JL_ID = tLoc.JL_ID, ( SELECT * FROM pa_student_super_hview( "EXPRESSION"=>'subtree("OJG777")' ) )STUD WHERE s.SUPER != 'PLATEAU' AND -- AND s.EMAIL_ADDR is not null -- AND s.NOTACTIVE = 'N' S.STUD_ID = STUD.RESULT_NODE AND LOWER(s.EMAIL_ADDR) NOT IN ('conversion@invalid.com', 'invalid@sap.com); /** and [security:PA_STUDENT s] Handling Connect by Queries - Example 2: Previous Script SELECT level l,s.stud_id,s.super,sys_connect_by_path(stud_id,' ; ') AS manager_hierarchyFROMpa_student s CONNECT BY PRIOR s.stud_id = s.super Standard Script SELECT stud.level l,s.stud_id,s.super,replace(stud.path,'/',';') AS manager_hierarchy FROM pa_student s,pa_student_super_hview stud WHERE s.stud_id = stud.result_node Do Not Use LISTAGG Use STRING_AGG instead. Previous Script LISTAGG(ap.ap_desc, ' | ') WITHIN GROUP( ORDER BY ap.ap_desc) FROM pa_assgn_prfl ap, pa_stud_assgn_prfl sap WHERE 1 = 1 AND ap.ap_id = sap.ap_id AND sap.stud_id = 'stud101' Standard Script STRING_AGG(ap.ap_desc, ' | ' ORDER BY ap.ap_desc) from PA_ASSGN_PRFL ap , PA_STUD_ASSGN_PRFL sap where 1=1 and ap.ap_id = sap.ap_id and sap.stud_id = 'stud123' 12 Do Not Use DBMS_LOB Use SUBSTR instead. Previous Script SELECT dbms_lob.substr(cbt.activity_tree,4000,1) activity_tree from pa_cbt_cpnt cbt where dbms_lob.substr(cbt.activity_tree,4000,1) IS NOT NULL Standard Script substr(cbt.activity_tree,4000,1) activity_tree from pa_cbt_cpnt cbt where substr(cbt.activity_tree,4000,1) IS NOT NULL Do Not Use Inner Keyword Inner is a reserved keyword. Previous Script SELECT inner.* --, SUBSTR(status_remday, 1,1) AS COMPLETE, -- SUBSTR(status_remday, INSTR(status_remday,'|',1)+1) Standard Script SELECT inner1.* --, SUBSTR(status_remday, 1,1) AS COMPLETE, -- SUBSTR(status_remday, INSTR(status_remday,'|',1)+1) Do Not Use WM_CONCAT Use STRING_AGG instead. Previous Script select WM_CONCAT (dept_name,' , ' ) from department Standard Script select STRING_AGG(dept_name,' , ' ) from department Do Not Use UNIQUE keyword Use DISTINCT instead. Previous Script SELECT UNIQUE stud_id FROM pa_student ; Standard Script SELECT DISTINCT stud_id FROM pa_student ; 13 Do Not Use LOCATION Keyword as Alias Use another string as the alias. Previous Script select stud_id from pa_student location; Standard Script select stud_id from pa_student my_alias; Do Not Use INSTR2 Use INSTR instead. Previous Script select instr2('demostring','d',1,1) from dual; Standard Script select instr('demostring','d',1,1) from dummy; Do Not Put Spaces in Logical Operators For example, if you have != or <=, do not put a space between ! and = Previous Script SELECT * from pa_student where pa_stud ! = 'AA'; Standard Script SELECT * from pa_student where pa_stud != 'AA'; Do Not Use Parentheses for Group By Clauses with Multiple Columns Previous Script select stud.stud_id,stud.fname from pa_student stud group by (stud.stud_id, stud.fname) Standard Script select stud.stud_id,stud.fname from pa_student stud group by stud.stud_id, stud.fname Do Not Select All Columns Select only the required columns. 14 Previous Script select * from pa_student Standard Script select stud_id from pa_student Use NVARCHAR Instead of varchar2 in Cast Functions Previous Script select cast(job_id as varchar2(4000) from dual; Standard Script select cast(job_id as NVARCHAR(4000) from dummy; Aliases with Special Characters Use double quotation marks around a column alias with special characters. Previous Script select su.user_value from pa_stud_user su where col_num = 130 and c.stud_id = su.stud_id) as Chaveárquico; Standard Script Select su.user_value from pa_stud_user su where col_num = 130 and c.stud_id = su.stud_id) as "CHAVEÁRQUICO"; Do Not Use Columns Names with Table Names Avoid using a table name with column names in SELECT statements. It adds unwanted schema name in the alias. For example, do not use the following: SELECT PA_INST.FNAME from PA_INST Use Consistent Data Types between DB Column Type and Report Designer Column Type Note the DATE field in the bounded column and the DATE-TIME in result set columns within RPTDESIGN. Do Not Use Case Statements with Mixed Datatypes. Use the to_char function in cases with mixed data types. For example, if the case statement resulting in a single column has integer and string values. 15 Previous Script select decode(eq.ATTEMPT_LIMIT, '0', 'Unlimited', eq.ATTEMPT_LIMIT) as ATTEMPT_LIMITS from PA_EQB_QUIZ eq Standard Script select * from (select (case when eq.ATTEMPT_LIMIT='0' then 'Unlimited' else to_char(eq.ATTEMPT_LIMIT) end) as ATTEMPT_LIMITS from PA_EQB_QUIZ eq ) Using Keywords LIMIT and CURRENT_DATE as Aliases Use double quotation marks when using keywords like LIMIT and CURRENT_DATE as aliases. Previous Script select LIMIT from PA_TRAINING_REQUEST_LIMIT; Standard Script select "LIMIT" from PA_TRAINING_REQUEST_LIMIT; Column Names in rptdesign file Use upper case for column names in rptdesign file while mapping. Do Not Use '&' in Column Alias Do not use '&' in column alias in SQL and in rptdesign file. Do Not Use Group By with Multiple Columns Inside Parentheses Previous Script select stud_id,fname from pa_student group by (stud_id,fname) Standard Script select stud_id,fname from pa_student group by stud_id,fname Using milliseconds functions Previous Script TimezoneUtil.getMillis(rev_dte) 16 Standard Script SECONDS_BETWEEN(TO_TIMESTAMP('1970-01-01 00:00:00'),c.rev_dte)*1000 Do Not Use CAST_TO_RAW in UTL_RAW Previous Script DBMS_LOB.INSTR (CSCMB.BOOKMARK, UTL_RAW.CAST_TO_RAW ('SStart;;'), 1, 1) SSTART Standard Script BINTOSTR(CAST(INSTR(BINTOSTR(CAST(CSCMB.BOOKMARK AS BINARY)),BINTOSTR(CAST('SStart;;' AS BINARY)),1,1) AS BINARY)) SSTART Using Federal Customers Functions This function is specifically used by federal customers and its equivalent is not available in our standard. PKG_CONN_EHRI_ENCRYPTION.ENCRYPT Using pkg_student.get_delm_stud_qual_stat_rmday This function is not recommended to be used due to performance issues Using Functions that Occur in Select Previous Script select LIMIT from PA_TRAINING_REQUEST_LIMIT; select pkg_student.get_delm_stud_qual_stat_rmday (sq.stud_id, sq.qual_id, sq.qual_id_root) AS status_remday from PA_STUD_QUAL_CPNT sqc, PV_COURSE cpt, PA_CMPL_STAT cs, PV_STUD_USER PSU, pa_student s, pa_user_preference userPref, pa_qual q Standard Script select stud_qual_remday.var AS status_remday from PA_STUD_QUAL_CPNT sqc right outer join ( select sq.stud_id, sq.qual_id, sq.assgn_dte, sq.qual_id_root, row_number() over (partition by sq.stud_id,sq.qual_id order by sq.assgn_dte) rnum from ( select sq.stud_id,sq.qual_id,sq.assgn_dte,sq.qual_id as qual_id_root from pa_stud_qual sq where 1=1 ) sq ) sq on sqc.STUD_ID = sq.stud_id and sqc.QUAL_ID = sq.qual_id and sqc.QUAL_ID_ROOT = sq.qual_id_root left outer join pkg_student_get_delm_stud_qual_stat_rmday_tab() stud_qual_remday on sq.qual_id = 17 stud_qual_remday.qual_id and sq.stud_id = stud_qual_remday.stud_id and sq.qual_id_root = stud_qual_remday.qual_id_root , PV_COURSE cpt, PA_CMPL_STAT cs, PV_STUD_USER PSU, pa_student s, pa_user_preference userPref, pa_qual q where sq.rnum = 1 and sq.qual_id = q.qual_id Using Functions that Occur in a Where Clause Previous Script select * from PA_STUD_QUAL_CPNT sqc, PV_COURSE cpt, PA_CMPL_STAT cs, PV_STUD_USER PSU, pa_student s, pa_user_preference userPref, pa_qual q, PA_STUD_QUAL_CPNT sq where sqc.STUD_ID (+)= sq.stud_id and sqc.QUAL_ID (+)= sq.qual_id and sqc.QUAL_ID_ROOT(+) = sq.qual_id_root and pkg_student.get_delm_stud_qual_stat_rmday (sq.stud_id, sq.qual_id, sq.qual_id_root) = 'status' OR PKG_STUDENT.get_delm_stud_qual_stat_rmday(sq.stud_id, sq.qual_id, sq.qual_id_root) = 'j' and sq.qual_id = q.qual_id Standard Script select sqc.*,cpt.*,cs.*,PSU.*,s.*,userPref.*,q.*,sq.* from PA_STUD_QUAL_CPNT sqc right outer join PA_STUD_QUAL_CPNT sq on sqc.STUD_ID = sq.stud_id and sqc.QUAL_ID = sq.qual_id and sqc.QUAL_ID_ROOT = sq.qual_id_root left outer join pkg_student_get_delm_stud_qual_stat_rmday_tab() stud_qual_remday on sq.qual_id = stud_qual_remday.qual_id and sq.stud_id = stud_qual_remday.stud_id and sq.qual_id_root = stud_qual_remday.qual_id_root , PV_COURSE cpt, PA_CMPL_STAT cs, PV_STUD_USER PSU, pa_student s, pa_user_preference userPref, pa_qual q where stud_qual_remday.var = 'status' OR stud_qual_remday.var = 'j' and sq.qual_id = q.qual_id Parameters in the Function Parameters should have the same aliasing to be handled by the converter. Previous Script - pkg_student.get_delm_stud_qual_stat_rmday (q.stud_id, q.qual_id, q.qual_id)-Handled -pkg_student.get_delm_stud_qual_stat_rmday (sq.stud_id, q.qual_id, q.qual_id) - Not Handled -pkg_student.get_delm_stud_qual_stat_rmday (q.stud_id, q.qual_id, q.qual_id_root)-Handled -pkg_student.get_delm_stud_qual_stat_rmday (sq.stud_id, q.qual_id, sq.qual_id_root)-Not Handled -pkg_student.get_delm_stud_qual_stat_rmday (sq.stud_id, q.qual_id_sub, sq.qual_id_root)-Not Handled Standard Script select * from pa_stud_qual sq, pa_qual q left outer join pkg_student_get_delm_stud_qual_stat_rmday_tab() stud_qual_remday on q.qual_id = stud_qual_remday.qual_id and q.stud_id = stud_qual_remday.stud_id and q.qual_id_root = stud_qual_remday.qual_id_root 18 Using a Function Wrapped with a System Function NVL,SUBSTR,INSTR are normally used functions within which the get_delm_stud_qual_stat_rmday is used Previous Script SELECT DISTINCT to_char(sysdate,'DD/MM/YYYY HH24:MI:SS') DATA_ESTRAZIONE, q.qual_id AS qual_id, sq.stud_id, decode(SUBSTR(pkg_student.get_delm_stud_qual_stat_rmday(sq.stud_id, sq.qual_id, sq.qual_id), 1,1),'N','NO','Y','SI') AS COMPLETED FROM pa_stud_qual sq, pa_student s, pa_qual q WHERE sq.stud_id = s.stud_id AND sq.qual_id = q.qual_id /**and [security:pa_student s]*/ AND TO_DATE(sq.LST_UPD_TSTMP, 'dd/mm/RR') <= TO_DATE('30/06/2016', 'dd/mm/RR') Standard Script SELECT DISTINCT to_char(CURRENT_TIMESTAMP,'DD/MM/YYYY HH24:MI:SS') DATA_ESTRAZIONE, q.qual_id AS qual_id, sq.stud_id, (case when SUBSTR(stud_qual_remday.var, 1,1)='N' then 'NO' when SUBSTR(stud_qual_remday.var, 1,1)='Y' then 'SI' end) AS COMPLETED FROM pa_stud_qual sq left outer join pkg_student_get_delm_stud_qual_stat_rmday_tab() stud_qual_remday on sq.qual_id = stud_qual_remday.qual_id and sq.stud_id = stud_qual_remday.stud_id and sq.qual_id = stud_qual_remday.qual_id_root , pa_student s, pa_qual q WHERE sq.stud_id AND sq.qual_id = s.stud_id = q.qual_id /**and [security:pa_student s]*/ AND to_timestamp(to_char(sq.LST_UPD_TSTMP, 'dd/mm/YYYY'),'dd/mm/YYYY') > to_timestamp('30/06/2016', 'dd/mm/YYYY') 19 Using Functions Above Multiple Unions Previous Script SELECT inner.*, pkg_student.get_delm_stud_qual_stat_rmday(inner.stud_id, inner.qual_id, inner.qual_id) AS status_remday FROM ( SELECT * FROM (SELECT * FROM (SELECT st.stud_id, st.super,Standard Script select sqc.*,cpt.*, Standard Script SELECT inner.*, SELECT innerHana7uobXetXQi.*, stud_qual_remday.var AS status_remday FROM (....... ) innerHana7uobXetXQi left outer join pkg_student_get_delm_stud_qual_stat_rmday_tab /*HANAVIEW_EXPRESSION () stud_qual_remday */ on innerHana7uobXetXQi.qual_id = stud_qual_remday.qual_id and innerHana7uobXetXQi.stud_id = stud_qual_remday.stud_id and innerHana7uobXetXQi.qual_id = stud_qual_remday.qual_id_root ) innerHana7uobXetXQi_1 System Tables Using the following table will result in an error when executing reports: ALL_TAB_COLUMNS , USER_TABLES ,USER_TAB_COLUMNS ,USER_TABLESPACES ,USER_TS_QUOTAS ,USER_CONSTRAINTS 20 Using a Column Alias PA_, PV_ , PKG_, PH_ , PS_ The column alias should not be starting with the value column. Using a Table Alias PA_, PV_ , PKG_, PH_ , PS_ The table alias should not be starting with the value column. Using a Column Alias with an Apostrophe Do not use an apostrophe in a column alias. This breaks the schema object strategy in the converter and the schema name may not appear in the query as expected. Ex: Instructor’s name Using a Numeric Function with SUBSTR TO_NUMBER(SUBSTR(status_remday, INSTR(status_remday,'|',1)+1)) TO_NUMBER expects a number or null argument. If the SUBSTR function returns an empty string, the query will fail. Queries that Result in Out of Memory – Example 1: Do not use projection SELECT statements within a projection SELECT statement. Instead use a JOIN (FROM Clause) or a WITH clause. Previous Script SELECT S.FNAME STUD_FNAME, S.LNAME STUD_LNAME, S.MI STUD_MI, (SELECT COUNT(*) AS TotalSurveys FROM PA_STUD_SURVEY pss, PA_CPNT_SURVEY psc WHERE psc.CPNT_SURVEY_ID = pss.CPNT_SURVEY_ID AND psc.survey_id = QS.survey_id ) TOTAL_SURVEY, (SELECT COUNT(*) AS TotalSurveys FROM PA_STUD_SURVEY pss, PA_CPNT_SURVEY psc WHERE psc.CPNT_SURVEY_ID = pss.CPNT_SURVEY_ID AND psc.survey_id = QS.survey_id AND pss.survey_status_id = 'COMPLETED' ) COMPLETED_SURVEY, 21 SS.SCH_ID SCHDULE_OFFERING, SR.STUD_COMMENTS STUDENT_COMMENTS, FROM PA_QUESTIONNAIRE_SURVEY QS LEFT OUTER JOIN PA_CPNT_SURVEY CS ON QS.SURVEY_ID = CS.SURVEY_ID RIGHT OUTER JOIN PA_STUD_SURVEY SS ON CS.CPNT_SURVEY_ID=SS.CPNT_SURVEY_ID Standard Script WITH TOTAL_SURVEY_q1 as ( SELECT count(*) cnt ,psc.survey_id FROM PA_STUD_SURVEY pss, PA_CPNT_SURVEY psc WHERE psc.CPNT_SURVEY_ID = pss.CPNT_SURVEY_ID group by psc.survey_id ), COMPLETED_SURVEY_q2 as ( SELECT COUNT(*) cnt ,psc.survey_id FROM PA_STUD_SURVEY pss, PA_CPNT_SURVEY psc WHERE psc.CPNT_SURVEY_ID = pss.CPNT_SURVEY_ID -- AND psc.survey_id = QS.survey_id AND pss.survey_status_id = 'COMPLETED' group by psc.survey_id ) SELECT S.FNAME STUD_FNAME, S.LNAME STUD_LNAME, S.MI STUD_MI, (SELECT cnt AS TotalSurveys FROM TOTAL_SURVEY_q1 psc WHERE survey_id = QS.survey_id ) TOTAL_SURVEY, (SELECT cnt AS TotalSurveys FROM COMPLETED_SURVEY_q2 psc WHERE psc.survey_id = QS.survey_id ) COMPLETED_SURVEY, SS.SCH_ID SCHDULE_OFFERING, SR.STUD_COMMENTS STUDENT_COMMENTS FROM PA_QUESTIONNAIRE_SURVEY QS LEFT OUTER JOIN PA_CPNT_SURVEY CS ON QS.SURVEY_ID = CS.SURVEY_ID RIGHT OUTER JOIN PA_STUD_SURVEY SS ON CS.CPNT_SURVEY_ID=SS.CPNT_SURVEY_ID Queries that Result in Out of Memory – Example 2: Previous Script Select ( 22 select user_value from ph_stud_user where stud_id = ST.STUD_ID and col_num and hist_create_tstmp = ( select max(hist_create_tstmp) from ph_stud_user where stud_id = ST.STUD_ID hist_create_tstmp <= (Select min(TX_DATE) from PA_FIN_TX where order_no = FOI.ORDER_NO) ) )as "Division ID", ( select user_value from ph_stud_user where stud_id = ST.STUD_ID and col_num and hist_create_tstmp = ( select max(hist_create_tstmp) from ph_stud_user where stud_id = ST.STUD_ID hist_create_tstmp <= (Select min(TX_DATE) from PA_FIN_TX where order_no = FOI.ORDER_NO) ) ) as "Division Desc", PU.USER_VALUE "Follow Up", ORG_STRUC1.Team "Team ID", OTeam.ORG_DESC "Team Name", FOC.ACCT_ID "Receiver CC (Cost Centre)", ST.FNAME "Attendee First Name", ST.LNAME "Attendee Last Name" From PA_STUDENT ST, PA_SHOPPING_ACCT SA, PA_STUDENT_FIN_ACCT SF, PA_ENROLL_SEAT ES, PA_ENROLL_SLOT SL, PA_FIN_ORDER_ITEM FOI, PA_SCHED S, PA_CPNT C, = 10 and col_num = 30 and = 30 and col_num = 30 and Standard Script Select ( select user_value from ph_stud_user where stud_id = OUTER2.STUD_ID and col_num = 10 and hist_create_tstmp = OUTER2."Division ID2" )as "Division ID", ( select user_value from ph_stud_user where stud_id = OUTER2.STUD_ID and col_num = 30 and hist_create_tstmp = OUTER2."Division Desc2", ) as "Division Desc", OUTER2."Follow Up", OUTER2."Team ID", OUTER2."Team Name", OUTER2."Receiver CC (Cost Centre)", OUTER2."Attendee First Name", OUTER2."Attendee Last Name" FROM ( Select ( select max(hist_create_tstmp) from ph_stud_user where stud_id = OUTER1.STUD_ID and col_num = 30 and hist_create_tstmp <= OUTER1."Division ID1" )as "Division ID2", 23 ( select max(hist_create_tstmp) from ph_stud_user where stud_id = OUTER1.STUD_ID and col_num = 30 and hist_create_tstmp <= OUTER1."Division Desc1", ) as "Division Desc2", OUTER1."Follow Up", OUTER1."Team ID", OUTER1."Team Name", OUTER1."Receiver CC (Cost Centre)", OUTER1."Attendee First Name", OUTER1."Attendee Last Name" from ( Select ( (Select min(TX_DATE) from PA_FIN_TX where order_no = FOI.ORDER_NO) )as "Division ID1", ( (Select min(TX_DATE) from PA_FIN_TX where order_no = FOI.ORDER_NO) ) as "Division Desc1", PU.USER_VALUE "Follow Up", ORG_STRUC1.Team "Team ID", OTeam.ORG_DESC "Team Name", FOC.ACCT_ID "Receiver CC (Cost Centre)", ST.FNAME "Attendee First Name", ST.LNAME "Attendee Last Name" From PA_STUDENT ST, PA_SHOPPING_ACCT SA, PA_STUDENT_FIN_ACCT SF, PA_ENROLL_SEAT ES, PA_ENROLL_SLOT SL, PA_FIN_ORDER_ITEM FOI, PA_SCHED S, PA_CPNT C, ................ ) OUTER1 ) OUTER2 24 www.sap.com/contactsap © 2018 SAP SE or an SAP affiliate company. All rights reserved. No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an SAP affiliate company. The information contained herein may be changed without prior notice. Some software products marketed by SAP SE and its distributors contain proprietary software components of other software vendors. National product specifications may vary. These materials are provided by SAP SE or an SAP affiliate company for informational purposes only, without representation or warranty of any kind, and SAP or its affiliated companies shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP or SAP affiliate company products and services are those that are set forth in the express warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty. In particular, SAP SE or its affiliated companies have no obligation to pursue any course of business outlined in this document or any related presentation, or to develop or release any functionality mentioned therein. This document, or any related presentation, and SAP SE’s or its affiliated companies’ strategy and possible future developments, products, and/or platform directions and functionality are all subject to change and may be changed by SAP SE or its affiliated companies at any time for any reason without notice. The information in this document is not a commitment, promise, or legal obligation to deliver any material, code, or functionality. All forward-looking statements are subject to various risks and uncertainties that could cause actual results to differ materially from expectations. Readers are cautioned not to place undue reliance on these forward-looking statements, and they should not be relied upon in making purchasing decisions. SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP SE (or an SAP affiliate company) in Germany and other countries. All other product and service names mentioned are the trademarks of their respective companies. See http://www.sap.com/corporate-en/legal/copyright/index.epx for additional trademark information and notices.