SAP Knowledge Base Article - Public

3691184 - Program Completion Percentage Fix Guide for Custom Reports

Symptom

Custom reports that display program completion percentage were using the GetProgramCompletionPercentage operator, which calculates the percentage at report runtime. This approach:

  • Causes performance degradation for reports with large datasets
  • Adds unnecessary computational overhead - Results in slower report generation times

This guide documents the changes required to fix program completion percentage calculation in custom reports. The fix addresses performance issues by using the pre-calculated PV_STUD_PROG_SEC_ENTRY_COMPL_DATA database view instead of calculating completion percentage at runtime using the GetProgramCompletionPercentage operator. This change can only be implemented on 2H 2025 versions of SuccessFactors Learning.

Note: SAP Support does not assist with modifying custom report queries, if you need assistance with updating any existing reports with these changes, please reach out to a report developer.

Environment

SAP SuccessFactors Learning

Resolution

The solution is to use the PV_STUD_PROG_SEC_ENTRY_COMPL_DATA database view to retrieve pre-calculated completion percentages directly from the database layer.

Prerequisites:

Before applying this fix, ensure:

  1. Your report uses program-related data from pa_stud_program table
  2. Your report displays program completion percentage

Step-by-Step Implementation Guide:

Step 1: Identify SQL Queries in Your Report

In ProgramStatusCSV.rptdesign, there were 2 main data sets:

  1. ProgramStatusDataSet - Main dataset without activity details
  2. ProgramStatusWithActivity - Dataset including program activities

Step 2: Modify SQL Queries - Add Table and Column

For EACH SQL query in your dataset, you need to make the following changes:

2.1 Add New Column to SELECT Statement

Location: In the SELECT clause
Action: Add spsec.completion_percentage as a new column

Before:

SELECT DISTINCT pc.seq_num,
    p.program_id,
    cpnt.cpnt_title AS program_title,
    -- ... other columns ...
    p.START_DTE,
    sp.STUD_PROGRAM_SYS_GUID
FROM pa_stud_program sp,
    -- ... other tables ...
After:

SELECT DISTINCT pc.seq_num,
    p.program_id,
    cpnt.cpnt_title AS program_title,
    -- ... other columns ...
    p.START_DTE,
    sp.STUD_PROGRAM_SYS_GUID,
    spsec.completion_percentage         -- NEW LINE ADDED along with comma in the above line
FROM pa_stud_program sp,
    -- ... other tables ...

2.2 Add New Table to FROM Clause

Location: In the FROM clause
Action: Add pv_stud_prog_sec_entry_compl_data spsec table

Before:

FROM pa_stud_program sp,
    pa_program p,
    pa_student s,
    pa_stud_cpnt pc,
    ps_program_type pt,
    pa_cpnt cpnt
WHERE -- ...
After:

FROM pa_stud_program sp,
    pa_program p,
    pa_student s,
    pa_stud_cpnt pc,
    ps_program_type pt,
    pa_cpnt cpnt,
    pv_stud_prog_sec_entry_compl_data spsec    -- NEW LINE ADDED along with comma in the above line
WHERE -- ...


2.3 Add JOIN Condition to WHERE Clause

Location: In the WHERE clause
Action: Add outer join condition to link the new view

Before:

WHERE p.PROGRAM_SYS_GUID = sp.PROGRAM_SYS_GUID
AND cpnt.CPNT_TYP_ID     = p.CPNT_TYP_ID
-- ... other conditions ...
AND pt.PROGRAM_TYPE_ID   = p.PROGRAM_TYPE
/** and p.program_id in [ProgramSearch] ...
After:

WHERE p.PROGRAM_SYS_GUID = sp.PROGRAM_SYS_GUID
AND cpnt.CPNT_TYP_ID     = p.CPNT_TYP_ID
-- ... other conditions ...
AND pt.PROGRAM_TYPE_ID   = p.PROGRAM_TYPE
AND sp.STUD_PROGRAM_SYS_GUID = spsec.STUD_PROGRAM_SYS_GUID(+)    -- NEW LINE ADDED along with comma in the above line
/** and p.program_id in [ProgramSearch] ...
Important Notes: - The (+) syntax indicates an outer join - Use this to ensure programs without completion data are still displayed

Step 3: Apply Changes to ALL Query Variations

The ProgramStatusCSV report had 4 different SQL queries that needed modification:

  1. Query 1: Programs NOT completed (without activities)
  2. Query 2: Programs completed (without activities)
  3. Query 3: Programs NOT completed (with activities)
  4. Query 4: Programs completed (with activities)

Action Required: Repeat Step 2.1, 2.2, and 2.3 for EACH query in your report.

Step 4: Update Data Bindings - Add Column Definition

After modifying the SQL queries, you need to add the new column to the dataset's result set definition.

4.1 Locate the Data Binding Section

In the XML structure of your .rptdesign file, find the <list-property name="computedColumns"> section for each affected dataset.

4.2 Add COMPLETION_PERCENTAGE Binding

Before:

<structure>
    <property name="name">PROGRAM_TYPE_LABEL</property>
    <text-property name="displayName">PROGRAM_TYPE_LABEL</text-property>
    <expression name="expression" type="javascript">dataSetRow["PROGRAM_TYPE_LABEL"]</expression>
    <property name="dataType">string</property>
</structure>
<!-- End of list -->

After:

<structure>
    <property name="name">PROGRAM_TYPE_LABEL</property>
    <text-property name="displayName">PROGRAM_TYPE_LABEL</text-property>
    <expression name="expression" type="javascript">dataSetRow["PROGRAM_TYPE_LABEL"]</expression>
    <property name="dataType">string</property>
</structure>
<structure>
    <property name="name">COMPLETION_PERCENTAGE</property>
    <text-property name="displayName">COMPLETION_PERCENTAGE</text-property>
    <expression name="expression" type="javascript">dataSetRow["COMPLETION_PERCENTAGE"]</expression>
    <property name="dataType">string</property>
</structure>
<!-- End of list -->

Before:

<structure>
    <property name="name">ENTRY_COMPL_DTE_1</property>
    <text-property name="displayName">ENTRY_COMPL_DTE</text-property>
    <expression name="expression" type="javascript">dataSetRow["ENTRY_COMPL_DTE"]</expression>
    <property name="dataType">date-time</property>
</structure>
<!-- End of list -->

After:

<structure>
    <property name="name">ENTRY_COMPL_DTE_1</property>
    <text-property name="displayName">ENTRY_COMPL_DTE</text-property>
    <expression name="expression" type="javascript">dataSetRow["ENTRY_COMPL_DTE"]</expression>
    <property name="dataType">date-time</property>
</structure>
<structure>
    <property name="name">COMPLETION_PERCENTAGE</property>
    <text-property name="displayName">COMPLETION_PERCENTAGE</text-property>
    <expression name="expression" type="javascript">dataSetRow["COMPLETION_PERCENTAGE"]</expression>
    <property name="dataType">string</property>
</structure>
<!-- End of list -->

Repeat this for BOTH data sets: - ProgramStatusDataSet - ProgramStatusWithActivity

Step 5: Update Report Display Elements - Change Operator

This is the most critical step where we switch from runtime calculation to using the pre-calculated value.

5.1 Locate the Completion Percentage Display Element

Find the data element or text element that displays the completion percentage. Look for properties like: - OPERATOR_NAME: GetProgramCompletionPercentage - OPERATOR_COLUMNS: STUD_PROGRAM_SYS_GUID

5.2 Change Operator Properties

Before:

<property name="SHOW_INPUPT">true</property>
<property name="OPERATOR_COLUMNS">STUD_PROGRAM_SYS_GUID</property>
<property name="OPERATOR_NAME">GetProgramCompletionPercentage</property>
<property name="whiteSpace">normal</property>
<property name="contentType">auto</property>
<text-property name="content"><![CDATA[[COMPLETION_PERCENTAGE]]]></text-property>

After:

<property name="SHOW_INPUPT">true</property>
<property name="OPERATOR_COLUMNS">COMPLETION_PERCENTAGE</property>
<property name="OPERATOR_NAME">FormatPercentageOperator</property>
<property name="whiteSpace">normal</property>
<property name="contentType">auto</property>
<text-property name="content"><![CDATA[[COMPLETION_PERCENTAGE]]]></text-property>

Key Changes: - OPERATOR_COLUMNS: Changed from STUD_PROGRAM_SYS_GUID to COMPLETION_PERCENTAGE - OPERATOR_NAME: Changed from GetProgramCompletionPercentage to FormatPercentageOperator

Why? - Previously, the operator took STUD_PROGRAM_SYS_GUID as input and calculated the percentage - Now, it takes the already-calculated COMPLETION_PERCENTAGE and just formats it

Apply this change to ALL locations where completion percentage is displayed (in ProgramStatusCSV, there were 2 locations).

Complete Change Summary

Changes Per Dataset (Apply to Each):

StepActionCount in ProgramStatusCSV
1Add spsec.completion_percentage to SELECT4 queries
2Add pv_stud_prog_sec_entry_compl_data spsec to FROM4 queries
3Add JOIN condition to WHERE clause4 queries
4Add COMPLETION_PERCENTAGE data binding2 datasets
5Change operator from GetProgramCompletionPercentage to FormatPercentageOperator2 display elements

Database View Information

View Name

PV_STUD_PROG_SEC_ENTRY_COMPL_DATA

Key Column

completion_percentage  - Pre-calculated percentage value

Join Key

STUD_PROGRAM_SYS_GUID - Links to pa_stud_program.STUD_PROGRAM_SYS_GUID

View Purpose

This view provides pre-calculated program completion percentages, eliminating the need for runtime calculation.

Quick Reference Card

SQL Changes (for each query):

  1. Add to SELECT clause: spsec.completion_percentage
  2. Add to FROM clause: pv_stud_prog_sec_entry_compl_data spsec
  3. 3. Add to WHERE clause: AND sp.STUD_PROGRAM_SYS_GUID = spsec.STUD_PROGRAM_SYS_GUID(+)

XML Changes:

<!-- Add data binding: -->
<structure>
    <property name="name">COMPLETION_PERCENTAGE</property>
    <text-property name="displayName">COMPLETION_PERCENTAGE</text-property>
    <expression name="expression" type="javascript">dataSetRow["COMPLETION_PERCENTAGE"]</expression>
    <property name="dataType">string</property>
</structure>

<!-- Change operator properties: -->
<property name="OPERATOR_COLUMNS">COMPLETION_PERCENTAGE</property>
<property name="OPERATOR_NAME">FormatPercentageOperator</property>

Appendix: Example Diff

Below is an example of the exact changes for one query:

 SELECT DISTINCT pc.seq_num,
     p.program_id,
     cpnt.cpnt_title AS program_title,
     -- ... other columns ...
     p.START_DTE,
-    sp.STUD_PROGRAM_SYS_GUID
+    sp.STUD_PROGRAM_SYS_GUID,
+    spsec.completion_percentage
 FROM pa_stud_program sp,
     pa_program p,
     pa_student s,
     pa_stud_cpnt pc,
     ps_program_type pt,
-    pa_cpnt cpnt
+    pa_cpnt cpnt,
+    pv_stud_prog_sec_entry_compl_data spsec
 WHERE p.PROGRAM_SYS_GUID = sp.PROGRAM_SYS_GUID
 AND cpnt.CPNT_TYP_ID     = p.CPNT_TYP_ID
 -- ... other conditions ...
 AND pt.PROGRAM_TYPE_ID   = p.PROGRAM_TYPE
+AND sp.STUD_PROGRAM_SYS_GUID = spsec.STUD_PROGRAM_SYS_GUID(+)

Keywords

program, completion, calculation, percentage, custom, report, performance, guide, correction, ptch-48629, programstatuscsv , KBA , LOD-SF-LMS-CRI , Custom Report Issues , Problem

Product

SAP SuccessFactors Learning all versions