SAP HANA Studio - ERP Q&A https://www.erpqna.com/tag/sap-hana-studio/ Trending SAP Career News and Guidelines Fri, 17 May 2024 13:15:54 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.1 https://i0.wp.com/www.erpqna.com/wp-content/uploads/2021/11/cropped-erpqna.png?fit=32%2C32&ssl=1 SAP HANA Studio - ERP Q&A https://www.erpqna.com/tag/sap-hana-studio/ 32 32 109149340 Unleashing the Power of Custom Widgets in SAP Analytics Cloud https://www.erpqna.com/unleashing-the-power-of-custom-widgets-in-sap-analytics-cloud/ Fri, 17 May 2024 13:15:49 +0000 https://www.erpqna.com/?p=84879 In today’s world where data is crucial, it’s really important to have analytics solutions that fit our business needs perfectly. With SAP Analytics Cloud (SAC), we can create custom analytical applications that are just right for our needs. One cool thing we can do with SAC is develop custom widgets. These widgets help us add […]

The post Unleashing the Power of Custom Widgets in SAP Analytics Cloud appeared first on ERP Q&A.

]]>
In today’s world where data is crucial, it’s really important to have analytics solutions that fit our business needs perfectly. With SAP Analytics Cloud (SAC), we can create custom analytical applications that are just right for our needs. One cool thing we can do with SAC is develop custom widgets. These widgets help us add more functions to SAC beyond what it already offers. In this blog post, I’m excited to talk about my experience making a custom SAC widget using a JSON file.

Prerequisites:

  1. Proficiency in JavaScript and JSON: Custom widgets in SAC are developed using JavaScript and defined using JSON files. Ensure that you have a good understanding of these languages and their syntax.
  2. Development Environment: Set up a development environment with the necessary tools for JavaScript development, such as a code editor (e.g., Visual Studio Code) and a web browser for testing.
  3. SAP Analytics Cloud Tenant: Access to an SAC tenant where you can create and test custom widgets. This may require coordination with your SAC administrator or IT department.
  4. Access to Documentation and Resources: Familiarize yourself with the official SAP documentation and resources related to custom widget development in SAC. This includes the SAC Developer Guide, API reference documentation, and any relevant tutorials or guides provided by SAP.
  5. Understanding of Widget Lifecycle and Events: Gain an understanding of the lifecycle of custom widgets in SAC, including initialization, rendering, data binding, and event handling. Understanding how widgets interact with the SAC environment will be crucial for developing robust and efficient solutions.
  6. Testing Environment: Set up a testing environment where you can deploy and test your custom widgets in a controlled environment before deploying them to production. This could be a sandbox or development environment within your SAC tenant.

Why Custom Widgets?

SAC provides a rich set of pre-built visualizations and functionalities. However, there are instances where users may require specialized visualizations or interactions that aren’t available out-of-the-box. This is where custom widgets shine. By creating custom widgets, users can tailor their analytics applications to address unique business requirements, enhancing decision-making and driving business outcomes.

Developing a Custom Widget

Developing a custom widget in SAC is a straightforward process. It begins with defining the widget’s properties and behaviours using a JSON file. This file specifies the widget’s appearance, data binding, interactions, and any custom logic required. Once the JSON file is defined, it can be uploaded to SAC, where it is rendered as a fully-functional widget within the application.

During the development process, I found the documentation provided by SAP to be comprehensive and user-friendly, guiding me through each step with clarity. Additionally, the SAC community forums proved to be an invaluable resource, offering insights and solutions to common challenges encountered during widget development.

Step 1:

Download the git bash using the below commands

Step 2:

Download the git angular file using the below command in git bash

Step 3:

Go into your file location and execute “npm i”

Step 4:

Once you installed the angular ,execute “node server.js” to enable localhost 3000

Step 5:

Execute “ngrok http 3000”

Step 6:

Copy the forwarding link from output and add “static/googleGauge.png” and “static/googleGauge. js” and paste in 7th and 15th line like in the below image

Step 7:

Search “Google gauge chart cdn” go to the link in the src from the below image and copy the js code

https://www.gstatic.com/charts/loader.js

Step 8:

Remove the selected lines in the below image and paste the code in googleGauge.js

Now your JSON file is ready.

Step 9:

Login to your SAC in Chrome/Edge

And open analytical application.

Step 10:

Navigate to Custom widget and use that ‘+’ icon to add your JSON file.

Step 11:

Once your JSON file successfully imported, again navigate to analytical application and create a new analytical application.

Note: As Classic Design Experience mode is deprecating, prefer optimised mode for better experience.

Step 12:

Go to insert -> custom widget -> choose your desire JSON file.

Step 13:

Once you added that JSON file the design you build in VS code will be replicated here. Then add input field, two buttons for plus and minus.

On-Initialise Code:

Minus Button Code:

Add Button Code:

Canvas Code:

Output:

I gave ‘123’ as Label and checked ‘+’, ‘-‘ buttons were working fine.

Limitations:

  1. Limited Browser Support: Custom widgets are rendered using web technologies such as HTML, CSS, and JavaScript, which may not be fully supported across all web browsers. Ensure compatibility with supported browsers, as specified by SAP, to avoid potential rendering issues for end-users.
  2. Performance Considerations: Custom widgets may introduce performance overhead, especially if they involve complex calculations or data processing. Be mindful of performance implications and optimize your custom widgets accordingly to ensure a smooth user experience.
  3. Dependency on SAC Updates: Custom widgets may rely on SAC APIs or underlying platform features, which could be subject to change with platform updates. Regularly review SAP’s release notes and announcements to stay informed about any changes that may impact your custom widgets.
  4. Limited Debugging Tools: Debugging custom widgets can be challenging, as SAC provides limited debugging tools compared to traditional web development environments. Utilize browser developer tools and logging mechanisms within your custom widgets to aid in troubleshooting and debugging.
  5. Security Considerations: Custom widgets execute within the SAC environment and have access to sensitive data. Ensure that your custom widgets adhere to best practices for security, such as data encryption, input validation, and protection against common web vulnerabilities like cross-site scripting (XSS) and injection attacks.
  6. Lack of Official Support for Third-Party Libraries: While SAC allows you to use third-party libraries within custom widgets, SAP does not officially support or guarantee compatibility with all libraries. Exercise caution when incorporating third-party dependencies and thoroughly test their compatibility with SAC.
  7. Limited Accessibility Features: SAC custom widgets may lack built-in accessibility features, such as keyboard navigation and screen reader support. Ensure that your custom widgets adhere to accessibility standards to provide an inclusive user experience for all users.
  8. Development Complexity: Developing custom widgets requires proficiency in web technologies such as JavaScript, HTML, and CSS. Additionally, understanding SAC’s widget API and platform-specific nuances adds to the development complexity. Invest time in learning and mastering these technologies to effectively develop and maintain custom widgets.
Rating: 0 / 5 (0 votes)

The post Unleashing the Power of Custom Widgets in SAP Analytics Cloud appeared first on ERP Q&A.

]]>
84879
SAP HANA DB Authorization concept https://www.erpqna.com/sap-hana-db-authorization-concept/ Fri, 29 Sep 2023 07:03:57 +0000 https://www.erpqna.com/?p=78511 SAP HANA SAP HANA is an in-memory, column-oriented, relational database management system developed and marketed by SAP SE. SAP HANA Security Sap Hana Security is protecting important data from unauthorized access and ensures that the standards and compliance meet as per the security standard. User Type in SAP HANA Depending on the different security policy […]

The post SAP HANA DB Authorization concept appeared first on ERP Q&A.

]]>
SAP HANA

SAP HANA is an in-memory, column-oriented, relational database management system developed and marketed by SAP SE.

SAP HANA Security

Sap Hana Security is protecting important data from unauthorized access and ensures that the standards and compliance meet as per the security standard.

User Type in SAP HANA

Depending on the different security policy there are two types of users in SAP HANA as below –

Technical User (DBA User) –

It is a user who directly work with SAP HANA database with necessary privileges. SAP HANA Database system provides following user by default as standard user –

  • SYSTEM
  • SYS
  • _SYS_REPO

Database or Real User:

Database user is a real person who works on SAP HANA. There are two types of Database user as below –

Standard User: This user can create objects in an own schema and reads data in system views. Standard User created with “CREATE USER” statement. PUBLIC role is assigned for read system views.

Restricted User: Restricted User connects to database through HTTP Only. ODBC/JDBC access for client connection must be enabled with SQL statement.

User creation in SAP HANA –

only database user with ROLE ADMIN privileges can create user and role in SAP HANA

Step 1) To create new user in SAP HANA Studio go to security tab as shown below and follow the following steps;

Go to security node.

Select Users (Right Click) -> New User.

User Creation

Step 2) A user creation screen appears.

Enter User Name.

Enter Password for the user.

These are authentication mechanism, by default User name / password is used for authentication.

By Clicking on the deploy Button user will be created.

SAP HANA privileges:

Privilege is the permission to execute certain actions. Total 6 types of privileges are available in SAP HANA

1)System privileges

2)Object privileges

3)Analytic privileges

4)Package privileges

5)Application privileges

6)Privileges on User

1- System Privileges

It controls normal system activity. System Privileges are mainly used for

  • Managing license
  • Managing version
  • Creating and Deleting Schema in SAP HANA Database
  • Managing Audit
  • Importing and Exporting content
  • Managing user and role in SAP HANA Database
  • Monitoring and tracing of SAP HANA database
  • Performing data backups
  • Maintaining Delivery Units
System Privilege

2- Object Privileges

Object Privileges are SQL privileges that are used to give authorization to read and modify database objects. Object privileges can be granted to catalog objects (table, view, etc.) or non-catalog objects (development objects).

Object Privilege

3- Analytic Privileges

Analytic Privileges are used to allow read access on data of SAP HANA Information model (attribute view, Analytic View, calculation View).

This privilege is evaluated during query processing.

Analytic Privileges grants different user access on different part of data in the Same information view based on user role.

Analytic Privileges are used in SAP HANA database to provide row level data Control for individual users to see the data is in the same view.

Analytical Privilege

4- Package Privileges

Package Privileges are used to provide authorization for actions on individual packages in SAP HANA Repository

Package Privilege

5- Application Privileges

Application Privileges are required in In SAP HANA Extended Application Services (SAP HANA XS) for access application.

Application Privilege

6- Privileges on User

It is an SQL Privileges, which can grant by the user on own user. ATTACH DEBUGGER is the only privilege that can be granted to a user.

Privileges on User

Define and Create Role

A role is a collection of privileges that can be granted to other users or role. The role includes privileges for database object & application and depending on the nature of the job. We can use the standard role as a template for creating a custom role. A role can contain following privileges –

System Privileges for administrative and development task

Object Privileges for database objects

Analytic Privileges for SAP HANA Information View

Package Privileges on repository packages

Application Privileges for SAP HANA XS applications.

Privileges on the user (For Debugging of procedure).

Role Creation

Step 1) In this step,

Go to Security node in SAP HANA System.

Select Role Node (Right Click) and select New Role.

Role Creation

Step 2) A role creation screen is displayed.

Give Role name under New Role Block.

Select Granted Role tab, and click “+” Icon to add Standard Role or exiting role.

Select Desired role

Step 3) In this step,

Selected Role is added in Granted Roles Tab.

Privileges can be assigned to the user directly by selecting System Privileges, object Privileges, Analytic Privileges, Package Privileges, etc.

Click on deploy icon to create Role.

Role assignment

Tick option “Grantable to other users and roles”, if you want to assign this role to other user and role.

Grant Role to User

Step 1) In this step, we will Assign Role to a user.

Go to User sub-node under Security node and double click it. User window will show.

Click on Granted roles “+” Icon.

A pop-up will appear, Search Role name which will be assign to the user.

Grant Role

Step 2) In this step, role will be added.

Step 3) In this step,

Click on Deploy Button.

A Message changed is displayed.

Resetting User Password

If user password needs to reset, then go to User sub-node under Security node and double click it. User window will show.

Step 1) In this step,

Enter new password.

Enter Confirm password.

Password reset

Step 2) In this step,

Click on Deploy Button.

A message changed is displayed.

Re-Activate/De-activate User

Go to User sub-node under Security node and double click it. User window will show.

There is De-Activate User icon. Click on it

User De-Activate

A confirmation message “Popup” will appear. Click on ‘Yes’ Button.

A message “User’ deactivated” will be displayed. The De-Activate icon changes with name “Activate user”. Now we can activate user from the same icon

SAP HANA License Management

The license key is required to use SAP HANA Database.

SAP HANA database support two types of license key –

Permanent License Key: Permanent license keys are valid till expiration date.

Temporary License Key: This is valid for 90 days and automatically installed with a new SAP HANA Database Installation.

SAP HANA License

Authorization of License Management

SAP HANA Auditing

SAP HANA Auditing features allow you to monitor and record action which is performed in SAP HANA System.

SAP HANA Auditing

Authorization for SAP HANA Auditing

Rating: 0 / 5 (0 votes)

The post SAP HANA DB Authorization concept appeared first on ERP Q&A.

]]>
78511
Handling Long Text – Migration Perspective https://www.erpqna.com/handling-long-text-migration-perspective/ Thu, 17 Aug 2023 12:11:16 +0000 https://www.erpqna.com/?p=76883 Long texts are a powerful asset in data management, providing detailed information beyond standard text descriptions. They allow businesses to capture essential details like ingredient descriptions, vendor remarks, and item details. However, long texts cannot be uploaded using data objects in the SAP Data Migration Cockpit (Migrate your Data Fiori App in S/4 HANA 2020). […]

The post Handling Long Text – Migration Perspective appeared first on ERP Q&A.

]]>
Long texts are a powerful asset in data management, providing detailed information beyond standard text descriptions. They allow businesses to capture essential details like ingredient descriptions, vendor remarks, and item details. However, long texts cannot be uploaded using data objects in the SAP Data Migration Cockpit (Migrate your Data Fiori App in S/4 HANA 2020).

Load Long text into SAP S4 HANA using BODS

Loading long texts into SAP S/4HANA can be a complex task, but SAP has provided an FM RFC_SAVE_TEXT that can serve this purpose. To load data using RFC_SAVE_TEXT, you may need to split long strings into equal parts, especially when dealing with tables like STXL and STXH in SAP.

Here’s a step-by-step guide to load long texts into SAP S/4HANA using SAP Data Services:

  • Source data Extraction: We have a string with a length of 1032 symbols, and our goal is to split it into equal pieces of 132 symbols each. This is necessary as we need to provide these equal parts as input to the FM RFC_SAVE_TEXT during the data extraction process.
Fig 1.Source data
  • Data Transformation: By utilizing the Row generation transform in a script and dataflow, we achieve the split of the long string into equal parts.
Fig2: Data Flow
  • Script: Initialize a variable with a maximum length of the long text using the script in BODS.
Fig3:Inside the script
  • Data Flow: Create a data flow that contains all the transformations to be done.
Fig4: Screenshot inside the data flow
  • Row Generation transform: Use the Row Generation transform to build the desired structure with equal parts of the long text. Set the Row number to start at 1, the Row count to equal the length of the longest string divided by the chunk size (round up the result), and the Join rank to 0.
Fig 5: Rowgen transform
  • Query transform “Split”: create a new Substring column of desirable size(split_size) and Map DI_ROW_ID from Row_Generation as shown below:

substr(<source_string>, (Row_Generation.DI_ROW_ID*<split_size>)+1,<split_size> )

where split_size is the length of the split data

Fig 6: Query split
  • Query transform “Not_Null”: For each long string, $GV_MAX_LEN indicates how many substrings are to be generated. In a source dataset containing multiple strings, shorter ones will generate NULL values. The WHERE tab should be set to exclude such records.
Fig 7:Query_not_null
  • Execute the job to get the multiple strings, as shown below
Fig 8: After transformation
  • Data Load: Use FM RFC_SAVE_TEXT to load data into SAP. Build Data flow as shown below:
Fig 9: Load flow

Use the SELECT DISTINCT statement to find the driver records (e.g., TDNAME) from the STXL table.

Fig 10:Qry_driver_rec

Qry_TEXT_LINES contains the data for the long text.

Fig 11:Qry_TEXT_LINES

Qry_Nest: Combine the data using driver records and create the structure as in Qry_TEXT_LINES which can be used in the FM RFC_SAVE_TEXT.

(e.g., Qry_TEXT_LINES.TDNAME =Qry_DRIVER_REC.TDNAME).

Fig 12:Query_NEST
Fig: 13Qry_TEXT_LINES

Import the FM RFC_SAVE_TEXT and call the FM RFC_SAVE_TEXT in the query.

Map the table TEXT_LINES to pass the data to SAP.

Fig 14:Qry_Call_RFC_SAVE_TEXT
Fig 15: FM-RFC_SAVE_TEXT
Fig 16: Messages from RFC
Fig 17: Loaded data

Read Long Text from SAP S4HANA

To read long text from SAP S/4HANA, you can use the function /BODS/READ_TEXT in SAP Data Services.

We need to extract TDNAME into the staging table in BODS. Then determine the parameters value TDID from CV03n t-code for the corresponding long text.

The function module /BODS/READ_TEXT in Data Services can be used to read data from SAP.

Fig 18:Job for reading data from SAP

Extract the TDNAME(Hearder data ) from STXL for the particular TDID and pass it through the FM READ_TEXT

Fig 19: Query_RFC
Fig 20: FM READ_TEXT

Map the corresponding fields from the query and click the next button.

After clicking the Next button, you should select the Columns you want to output from the function.

The required long text data is available in the LINES column and there it should be selected as the output column.

Fig 21: Output Parameter

Un-nest the LINES table by dragging all of its columns out of the Schema In section and placing them in the Schema Out section. TDLINE field contains the data.

Next, create a target table and execute the job.

Fig 22: Long text from SAP

The function will return the multi line long text data.

Rating: 0 / 5 (0 votes)

The post Handling Long Text – Migration Perspective appeared first on ERP Q&A.

]]>
76883
SAP HANA SLT – Performance Tuning on customer developed ABAP program https://www.erpqna.com/sap-hana-slt-performance-tuning-on-customer-developed-abap-program/ https://www.erpqna.com/sap-hana-slt-performance-tuning-on-customer-developed-abap-program/#respond Mon, 26 Jul 2021 07:57:47 +0000 https://www.erpqna.com/?p=51394 Introduction In this post, I would like to share one of my project experience on performance tuning for Customer developed ABAP program from 38% improvement to 260%+ improvement after implemented SAP HANA SLT side car. I will share some of the techniques for using sap transactions (SCI, SE30, etc) to analyze the performance bottleneck for […]

The post SAP HANA SLT – Performance Tuning on customer developed ABAP program appeared first on ERP Q&A.

]]>
Introduction

In this post, I would like to share one of my project experience on performance tuning for Customer developed ABAP program from 38% improvement to 260%+ improvement after implemented SAP HANA SLT side car.

I will share some of the techniques for using sap transactions (SCI, SE30, etc) to analyze the performance bottleneck for further improvement with screens shoot captured from my work in the past which I had helped to implement SAP HANA SLT and fine tuning a customer developed report ZFI05SBL with side car.

Background – Performance Measure for customer program after implement SLT

Remark: ZFI05SBL (original program before tuning); ZFI05SBL_N (revision program tuned for SAP HANA SLT Side car)

Background: We found that there was only a slight improvement on performance (i.e. 38% – 40%) after implement side car with SAP HANA SLT for the initial performance measure for customer developed program.

Since the customer wasn’t happy about the result and refused to sign-off UAT, I had used SAP transactions SCI, SE30, ST05 for analyzed the performance bottleneck and identify the area for further improvement.

Analysis Step 1 – Checking from Basis perspective

Before we jump into application analysis and tuning, I would suggest to start performance analysis on some basic area. (i.e. system configuration, parameter settings, etc) which is important as sometimes incorrect / non-optimal configuration in system setting may cause application performance degrade.

Most of the time, I would start using SM66 or SM50 to monitor the SAP processes running in the SAP system and view the details of the processes which I suspect with performance bottleneck that had been running for long time.

You may check for following:

  • Actions running
  • Records update
  • Activities
  • Memory statistic

(Tips 1: Heap Memory à lack of memory on ABAP instance)

(Tips 2: If program running for long time without records increases, this may be due to bottleneck on database resource.)

Example: Use SM50 / SM66 to review Memory Statistic & DB statistic for long running processes

In addition, I also reviewed the SAP HANA database replication processes and found that there were times that the replication processes were pending on HANA database during non-office hours.

Example: Found SAP HANA SLT process pending
Example: SM37 – Found replication job were in delay status
Example: Check SM50 and found BTC processes were fully occupied during non-office hours

Finding 1 – Example: Replication Process pending & delayed due to lack of background process

After checking the SM37 and SM50, I found that replication job had been delayed due to all background processes had been occupied during table replications in the non-office hours.

Therefore, I had tuned the system parameters in SAP operation mode (Tcode: RZ03) for increase number of work processes for background jobs and fine tuned the SAP HANA SLT replication server parameters.

Example: RZ03 – Increase BTC process in operation mode
Example: Tuning SAP LT Replication Server parameter

Analysis Step 2 – Capture original program performance as baseline

After we confirmed that the system configuration and resources is optimal, we may start to measure the customer developed program performance before tuning as baseline figures.

I had used 2 transaction ST03N and SM37 for measure the program execution time.

Example: ST03N – Workload Analysis (Transaction Profile)

Workload Analysis (ST03N)

I used transaction ST03N Transaction profile for review performance before and after SLT HANA replication and ABAP accelerator and checked for program behavior before switch the program to run on HANA database table. These figures can be used for troubleshoot and use for identify performance bottleneck.

Job Overview (SM37)

I used transaction SM37 to review the job execution time before and after using SAP LT replication on HANA wand ABAP accelerator.

Example: Program variant used for performance test
Example: Use SM37 to measure program execution time

We found that the performance is improved if retrieved data with 3 months and 8 site for this report.

Time 1:

Original Execution Time: 9596

Time 2:

SLT Execution Time: 6941

((T2 / T1) – 1 ) * 100 = 38%

The 1st testing result is improved 38% for replicate tables on KONP, MARA, MBEW and MBEWH

Since we see that the performance is not improved a lot with ABAP Accelerator and SAP LT HANA replication. We perform the code inspection for this program to check for area need to be tuned.

Analysis Step 3 – SAP Code Inspector

I had used the SAP Code Inspector for analyzed the customer developed program for identify the program code required performance tuning.

Example: Create Check Variant for SAP Code Inspector
Example: Review SAP Code Inspector result

Finding 2 – Example found some SQL statement are checking on some tables not replicated with SLT.

I had reviewed the SAP code inspector result and identified that there are some code required tuning for optimal performance for running in SAP HANA. In addition, I also found that some of the tables used in where clause filter had not replicated to SLT. Therefore, I had added the tables for replication and tuned the ABAP code per SAP recommendation.

  • Update ABAP Code per SAP recommendation for code change in HANA environment.
  • Include the tables for SLT replication and side car
Example: Sample Tuning – Revised coding per SAP recommendation on HANA platform
Example: Sample Tuning – Revised the statement and include the condition records tables into SAP SLT replication.
Example: Sample Tuning – Check the statement and ensure inner join table are included in SAP LT replications.
Example: Sample Tuning – Included the tables used in inner join for SAP LT replication
Example: Sample Tuning – Included the table for side car

Review Program execution time after tuning

After performed the tuning, I had execute the program with SM37 at different timeslot with same program variant selection to verify the performance had improved after tuning.

This time I found that the program execution time had improved around 95% to 104% for 3rd to 6th round of testing in different timeslot.

No. Time 1  Time 2  Ratio   % Improvement 
1st Round  9596 6941 1.38 38.25%
2nd Round  9596  6888  1.39  39.31% 
3rd Round  9596  4685  2.05  104.82% 
4th Round  9596  4737  2.03  102.58% 
5th Round  9596  4719  2.03  103.35% 
6th Round  9596  4903  1.96  95.72% 

Remark: Calculation of % of Improvement: ((T2/T1) – 1 * 100%)

1st – 2nd round – execution after using activate ABAP accelerator.

3rd – 6th round – execute after tuning by adding additional tables for push down database operations to HANA database.

Example: Use SM37 to review program execution time after tuning

Review ABAP Analysis (SE30)

Although I had verified that the program execution time had improved, I had further checked the ABAP program with transaction SE30 for identified the area can be further fine tuned.

Tips: I usually check on the Net(%) for identify the area should be review for further improvement.

Example: Review SE30 ABAP Analysis result

Final Review in program execution time after deployment to production system

At last we had compared the original program and the fine tuned program in production system.

We measured the program execution time between original program and the fine tuned side car version using identical program variant for selection and found significant improvement as below for 8th to 12th round of the performance testing.

No. Time 1  Time 2  Ratio   % Improvement 
1st Round  9596 6941 1.38 38.25%
2nd Round  9596  6888  1.39  39.31% 
3rd Round  9596  4685  2.05  104.82% 
4th Round  9596  4737  2.03  102.58% 
5th Round  9596  4719  2.03  103.35% 
6th Round  9596  4903  1.96  95.72% 
7th Round 9596 7967 1.20 20.45%
8th Round 9596 1042 9.21 820.92%
9th Round 9596 1190 8.06 706.39%
10th Round 9596 1554 6.18 517.50%
11th Round 9596 1166 8.23 722.98%
12th Round 9596 2602 3.69 268.79%

Example: Use SM37 to review program execution in production system.

Remark: ZFI055SBL is original program; ZFI055SBL_N is the tuned side car version with SAP HANA SLT.

In conclusion, we may improve the customer developed program using SAP HANA SLT (side car) with optimal setting in replication server & SAP server.

Rating: 0 / 5 (0 votes)

The post SAP HANA SLT – Performance Tuning on customer developed ABAP program appeared first on ERP Q&A.

]]>
https://www.erpqna.com/sap-hana-slt-performance-tuning-on-customer-developed-abap-program/feed/ 0 51394
Excel File Upload From SAP Analytics Cloud Analytic Application https://www.erpqna.com/excel-file-upload-from-sap-analytics-cloud-analytic-application/ https://www.erpqna.com/excel-file-upload-from-sap-analytics-cloud-analytic-application/#respond Tue, 15 Sep 2020 12:21:39 +0000 https://www.erpqna.com/?p=36415 There was a requirement to upload an Excel file directly from the SAC Analytic Application. I would like to share here how I did it. We will create a custom widget in SAC with library from SheetJS with a little modification. We will also create table, view and stored procedure in HANA. I am using […]

The post Excel File Upload From SAP Analytics Cloud Analytic Application appeared first on ERP Q&A.

]]>
There was a requirement to upload an Excel file directly from the SAC Analytic Application. I would like to share here how I did it.

We will create a custom widget in SAC with library from SheetJS with a little modification. We will also create table, view and stored procedure in HANA. I am using HANA Classic for this purpose.

In a nutshell, we need to create the following modules:

  • HANA Table and Calculation View
  • HANA Stored Procedure
  • HANA XSJS
  • SAC Custom Widget
  • SAC Analytic Application

HANA Table and View

Create HANA table SACXLSX.hdbtable. This table will store the data from Excel file.

// To define an HDB table with main sql type columns, you can use the following code.
// In the example below a schema should exist.   

table.schemaName = "COMMON";
table.tableType = COLUMNSTORE; // ROWSTORE is an alternative value

table.columns = [
    {name = "DATE"; sqlType = DATE;  comment = "date - YYYYMMDD";},
    {name = "COUNTRY_CODE"; sqlType = NVARCHAR; length = 2; comment = "Country Code";},
    {name = "COMPANY_CODE"; sqlType = NVARCHAR; length = 10; comment = "Company Code";},
    {name = "TYPE"; sqlType = NVARCHAR; length = 30; comment = "Type of Data";},
    {name = "VALUE_DATE"; sqlType = DATE; comment = "Value Date - YYYYMMDD";},
    {name = "AMOUNT"; sqlType = DOUBLE; comment = "Amount";},
    {name = "CURRENCY"; sqlType = NVARCHAR; length = 3; comment = "Currency";},
    {name = "COMMENTS"; sqlType = NVARCHAR; length = 100; comment = "Comments";},  
    {name = "LOCK_FLAG"; sqlType = NVARCHAR; length = 10; comment = "Lock Flag";}
];

Create HANA Calculation View TC_SACXLSX.calculationview. We will later create the model in SAC Analytic Application with this view.

HANA Stored Procedure

Create stored procedure insertData.hdbprocedure to insert data to table SACXLSX.

PROCEDURE "insertData" ( 
	in DATE DATE,
	in COUNTRY_CODE NVARCHAR(2),
	in COMPANY_CODE NVARCHAR(10),
	in TYPE NVARCHAR(30),
	in VALUE_DATE DATE,
	in AMOUNT DOUBLE,
	in CURRENCY NVARCHAR(3),
	in COMMENTS NVARCHAR(100),
	in LOCK_FLAG NVARCHAR(1)
) 
	LANGUAGE SQLSCRIPT
	SQL SECURITY INVOKER 
	--DEFAULT SCHEMA <default_schema_name>
	--READS SQL DATA AS
	AS -- "READS SQL DATA " removed  
BEGIN
/***************************** 
	Write your procedure logic 
 *****************************/
insert into
	"SACXLSX"
	values 
		(
			DATE,
			COUNTRY_CODE,
			COMPANY_CODE,
			TYPE,
			VALUE_DATE,
			AMOUNT,
			CURRENCY,
			COMMENTS,
			LOCK_FLAG
		);
END;

HANA XSJS

Create XSJS processData.xsjs. This server-side scripting will process the data from the HTTP Post request from the SAC custom widget and calls the store procedure InsertData to insert the records to table.

try {
	var content = $.request.body.asString();	
	var data = JSON.parse(content);	
	var result = ""; 
	var DATE;
	var COUNTRY_CODE;
	var COMPANY_CODE;
	var TYPE;
	var VALUE_DATE;
	var AMOUNT;
	var CURRENCY;
	var COMMENTS;
	var LOCK_FLAG;	 
	
	var conn = $.hdb.getConnection({ "xssqlcc": "anonuser"}); 
	var procedureCall = conn.loadProcedure("insertData");
	
	for(var i = 0; i <data.length; i++) {
		DATE = data[i].DATE;
		COUNTRY_CODE = data[i].COUNTRY_CODE;
		COMPANY_CODE = data[i].COMPANY_CODE;
		TYPE = data[i].TYPE;
		VALUE_DATE = data[i].VALUE_DATE;
		AMOUNT = data[i].AMOUNT;
		CURRENCY = data[i].CURRENCY;
		COMMENTS = data[i].COMMENTS;
		LOCK_FLAG = data[i].LOCK_FLAG;
		
		procedureCall(DATE, COUNTRY_CODE, COMPANY_CODE, TYPE, VALUE_DATE, AMOUNT, CURRENCY, COMMENTS, LOCK_FLAG);		
	}
	
	conn.commit();
	conn.close();
	
	$.response.headers.set("Access-Control-Allow-Origin", "*");
	$.response.contentType = "application/json";
	$.response.setBody(JSON.stringify(data));
	$.response.returnCode = 200;	
} catch (err) {
	$.response.headers.set("Access-Control-Allow-Origin", "*");
	$.response.contentType = "application/json";
        $.response.setBody(JSON.stringify(err.message));
        $.response.returnCode = 200;
}

SAC Custom Widget

In the custom widget, we will load the external library with the modified code from SheetJS, xslx.js.

onCustomWidgetAfterUpdate(changedProperties) {
  var that = this;

  let xlsxjs = "http://localhost/SAC/sacexcel/xlsx.js";
  async function LoadLibs() {
    try {
      await loadScript(xlsxjs, _shadowRoot);
    } catch (e) {
      console.log(e);
    } finally {
      loadthis(that, changedProperties);
    }
  }
  LoadLibs();
}

We’ll create an XMLView with SAPUI5 SimpleForm and FileUploader.

Using SheetJS library, we parse the data from the uploaded Excel file and perform the validation to make sure the data is valid.

Once the data is validated, we will send it to HANA processData.xsjs with POST method.

We’ll wait until the data is completely processed and once is done, we’ll refresh the SAC model.

function loadthis(that, changedProperties) {
  var that_ = that;

  widgetName = changedProperties.widgetName;
  if (typeof widgetName === "undefined") {
    widgetName = that._export_settings.title.split("|")[0];
  }

  div = document.createElement('div');
  div.slot = "content_" + widgetName;

  if (that._firstConnection === 0) {
    let div0 = document.createElement('div');
    div0.innerHTML = '<?xml version="1.0"?><script id="oView_' + widgetName + '" name="oView_' + widgetName + '" type="sapui5/xmlview"><mvc:View height="100%" xmlns="sap.m" xmlns:u="sap.ui.unified" xmlns:f="sap.ui.layout.form" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" controllerName="myView.Template"><f:SimpleForm editable="true"><f:content><Label text="Upload"></Label><VBox><u:FileUploader id="idfileUploader" width="100%" useMultipart="false" sendXHR="true" sameFilenameAllowed="true" buttonText="" fileType="XLSM" placeholder="" style="Emphasized" change="onValidate"></u:FileUploader></VBox></f:content></f:SimpleForm></mvc:View></script>';
    _shadowRoot.appendChild(div0);

    let div1 = document.createElement('div');
    div1.innerHTML = '<?xml version="1.0"?><script id="myXMLFragment_' + widgetName + '" type="sapui5/fragment"><core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core"><SelectDialog title="Partner Number" class="sapUiPopupWithPadding"  items="{' + widgetName + '>/}" search="_handleValueHelpSearch"  confirm="_handleValueHelpClose"  cancel="_handleValueHelpClose"  multiSelect="true" showClearButton="true" rememberSelections="true"><StandardListItem icon="{' + widgetName + '>ProductPicUrl}" iconDensityAware="false" iconInset="false" title="{' + widgetName + '>partner}" description="{' + widgetName + '>partner}" /></SelectDialog></core:FragmentDefinition></script>';
    _shadowRoot.appendChild(div1);

    let div2 = document.createElement('div');
    div2.innerHTML = '<div id="ui5_content_' + widgetName + '" name="ui5_content_' + widgetName + '"><slot name="content_' + widgetName + '"></slot></div>';
    _shadowRoot.appendChild(div2);

    that_.appendChild(div);

    var mapcanvas_divstr = _shadowRoot.getElementById('oView_' + widgetName);
    var mapcanvas_fragment_divstr = _shadowRoot.getElementById('myXMLFragment_' + widgetName);

    Ar.push({
      'id': widgetName,
      'div': mapcanvas_divstr,
      'divf': mapcanvas_fragment_divstr
    });
  }

  that_._renderExportButton();

  sap.ui.getCore().attachInit(function() {
    "use strict";

    //### Controller ###
    sap.ui.define([
      "jquery.sap.global",
      "sap/ui/core/mvc/Controller",
      "sap/ui/model/json/JSONModel",
      "sap/m/MessageToast",
      "sap/ui/core/library",
      "sap/ui/core/Core",
      'sap/ui/model/Filter',
      'sap/m/library',
      'sap/m/MessageBox',
      'sap/ui/unified/DateRange',
      'sap/ui/core/format/DateFormat',
      'sap/ui/model/BindingMode',
      'sap/ui/core/Fragment',
      'sap/m/Token',
      'sap/ui/model/FilterOperator',
      'sap/ui/model/odata/ODataModel',
      'sap/m/BusyDialog'
    ], function(jQuery, Controller, JSONModel, MessageToast, coreLibrary, Core, Filter, mobileLibrary, MessageBox, DateRange, DateFormat, BindingMode, Fragment, Token, FilterOperator, ODataModel, BusyDialog) {
      "use strict";

      var busyDialog = (busyDialog) ? busyDialog : new BusyDialog({});

      return Controller.extend("myView.Template", {

        onInit: function() {
          console.log(that._export_settings.title);
          console.log("widgetName:" + that.widgetName);

          if (that._firstConnection === 0) {
            that._firstConnection = 1;
          }
        },

        onValidate: function(e) {

          var fU = this.getView().byId("idfileUploader");
          var domRef = fU.getFocusDomRef();
          var file = domRef.files[0];
          var this_ = this;

          var oModel = new JSONModel();
          oModel.setData({
            result_final: null
          });

          var reader = new FileReader();
          reader.onload = async function(e) {
            var strCSV = e.target.result;

            var workbook = XLSX.read(strCSV, {
              type: 'binary'
            });

            var result_final = [];
            var result = [];
            var correctsheet = false;

            workbook.SheetNames.forEach(function(sheetName) {
              if (sheetName === "Sheet1") {
                correctsheet = true;
                var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]);
                if (csv.length) {
                  result.push(csv);
                }
                result = result.join("[$@~!~@$]")
              }
            });

            if (correctsheet) {
              var lengthfield = result.split("[$@~!~@$]")[0].split("[#@~!~@#]").length;
              console.log("lengthfield: " + lengthfield);

              var total = this_.getView().byId("total");
              var rec_count = 0;

              var len = 0;
              if (lengthfield === 9) {
                for (var i = 1; i < result.split("[$@~!~@$]").length; i++) {
                  if (result.split("[$@~!~@$]")[i].length > 0) {

                    var rec = result.split("[$@~!~@$]")[i].split("[#@~!~@#]");
                    if (rec.length > 0) {
                      len = rec[0].trim().length + rec[1].trim().length + rec[2].trim().length + rec[3].trim().length + rec[4].trim().length + rec[
                        5].trim().length + rec[6].trim().length + rec[7].trim().length + rec[8].trim().length;
                      if (len > 0) {
                        rec_count = rec_count + 1;
                        result_final.push({
                          'ID': i,
                          'DATE': rec[0].trim(),
                          'COUNTRY_CODE': rec[1].trim(),
                          'COMPANY_CODE': rec[2].trim(),
                          'TYPE': rec[3].trim(),
                          'VALUE_DATE': rec[4].trim(),
                          'AMOUNT': rec[5].trim().replace(/[,]/g, ""),
                          'CURRENCY': rec[6].trim(),
                          'COMMENTS': rec[7].trim().replace(/["'\n\r]/g, ""),
                          'LOCK_FLAG': rec[8].trim(),
                        });
                      }
                    }
                  }
                }

                if (result_final.length === 0) {
                  fU.setValue("");
                  MessageToast.show("There is no record to be uploaded");
                } else if (result_final.length >= 2001) {
                  fU.setValue("");
                  MessageToast.show("Maximum records are 2000.");
                } else {
                  // Bind the data to the Table
                  oModel = new JSONModel();
                  oModel.setSizeLimit("5000");
                  oModel.setData({
                    result_final: result_final
                  });

                  var oModel1 = new sap.ui.model.json.JSONModel();
                  oModel1.setData({
                    fname: file.name,
                  });
                  console.log(oModel);

                  var oHeaders = {
                    "Authorization": "Basic XXXXXXX",
                    "Content-Type": "application/x-www-form-urlencoded"
                  }

                  var oModel = new JSONModel();

                  console.log(result_final);
                  oModel.loadData("processData.xsjs", JSON.stringify(result_final), true, 'POST', false, true, oHeaders);

                  oModel.attachRequestCompleted(function() {
                    var result = oModel.getData();
                    console.log(result);

                    _result = result;

                    that._firePropertiesChanged();
                    this.settings = {};
                    this.settings.result = "";

                    that.dispatchEvent(new CustomEvent("onStart", {
                      detail: {
                        settings: this.settings
                      }
                    }));
                  });
                  fU.setValue("");
                }
              } else {
                fU.setValue("");
                MessageToast.show("Please upload the correct file");
              }
            } else {
              console.log("Error: wrong xlsx template");
              MessageToast.show("Please upload the correct file");
            }
          };

          if (typeof file !== 'undefined') {
            reader.readAsBinaryString(file);
          }
        },

        wasteTime: function() {
          busyDialog.open();
        },

        runNext: function() {
          busyDialog.close();
        },

      });
    });

    console.log("widgetName Final:" + widgetName);
    var foundIndex = Ar.findIndex(x => x.id == widgetName);
    var divfinal = Ar[foundIndex].div;
    console.log(divfinal);

    //### THE APP: place the XMLView somewhere into DOM ###
    var oView = sap.ui.xmlview({
      viewContent: jQuery(divfinal).html(),
    });

    oView.placeAt(div);
    if (that_._designMode) {
      oView.byId("idfileUploader").setEnabled(false);
    }
  });
}

SAC Analytic Application

Insert the custom widget Excel_1 and table Table_1 with the model from TC_SACXLSX.calculationview.

In Excel_1 widget onStart() event, add the following code to refresh the model:

Table_1.getDataSource().refreshData();
Rating: 0 / 5 (0 votes)

The post Excel File Upload From SAP Analytics Cloud Analytic Application appeared first on ERP Q&A.

]]>
https://www.erpqna.com/excel-file-upload-from-sap-analytics-cloud-analytic-application/feed/ 0 36415
Using SAP BW characteristic attributes in SAP PaPM https://www.erpqna.com/using-sap-bw-characteristic-attributes-in-sap-papm/ https://www.erpqna.com/using-sap-bw-characteristic-attributes-in-sap-papm/#respond Thu, 10 Sep 2020 10:50:28 +0000 https://www.erpqna.com/?p=36226 SAP Profitability and Performance Management (PaPM) is a flexible solution due to its independency of any data models. PaPM can be integrated with the help of information functions such as Model Table, Model View, Model BW to various data sources such as SAP HANA Tables, Data Dictionary Tables, SAP BW aDSOs and so on. Since […]

The post Using SAP BW characteristic attributes in SAP PaPM appeared first on ERP Q&A.

]]>
SAP Profitability and Performance Management (PaPM) is a flexible solution due to its independency of any data models. PaPM can be integrated with the help of information functions such as Model Table, Model View, Model BW to various data sources such as SAP HANA Tables, Data Dictionary Tables, SAP BW aDSOs and so on.

Since I have mentioned SAP BW as possible data source, from SAP BW perspective, will it not be fantastic if PaPM will also make use and utilize more than just BW objects? Like for example, BW functionalities which are commonly used in SAP BW such as Attributes of InfoObjects?

Good news – PaPM does!

In this blog I will present how to use Attributes of InfoObjects by splitting the topic into two main parts:

  1. Attributes – quick and simple overview – could be helpful for users that don’t work in BW yet. Feel free to skip this part if you know what attribute of InfoObject means.
  2. How to use navigational attributes in PaPM – quick guide which will provide solution of using attributes.

1. Attributes – quick and simple overview

Attributes in SAP BW are characteristics that describe certain properties for another characteristic which has the “Master Data” property . Primarily used to describe objects such as materials, G/L accounts, cost centers, customers, etc. The attributes also provide additional information about characteristic which they are assigned to.

After reading this definition it is time for example to clear things out:

You have a material with number MT14.4365.A. And you cannot tell anything more than number (unless you are manufacturing this thing for 5 years). You don’t know what the type of this particular material is, in which material group it is, what the length/weight of it is and so on. But such properties like material type, material group, length, weight are intrinsic to this material and meaningful for your business data management, therefore they should be attributed to this material from the beginning (of business settings).

Any InfoObjects like characteristic, key figure and unit normally can be attributed to a characteristic in its „Attributes” tab. They can also be used in any info provider. But characteristic defined in SAP BW with property checkbox marked as Attribute only could only be used as an attribute – using it in info provider is not possible.

Fig. 1 Attribute only checkbox in BW Modeling Tools

Basically speaking, we can divide attributes into 2 types:

  • Display Attributes – are completely dependent on the main characteristic, they can only be presented in reporting tools with the main characteristic.
  • Navigational Attributes – these attributes act as “normal” characteristic at query level in reporting (filtering, restricting, etc. is possible).

Key figures are always display attributes, characteristics can act in both way: as display attribute or navigational attribute.

For tracking history/changes in assignment of attribute value to main characteristic Time dependency can be defined in SAP BW. It enables to maintain changing values of attributes based on time period. Key date will define what value it has to bring from the time dependent attribute table. I will describe time-dependent attributes and how to use them in the next blog post.

Attributes defined in SAP BW for characteristics can also be used in SAP PaPM. Display attributes in SAP PaPM are always available in the associated query of all kinds of functions (when viewed in Analyze) and can be added/display, if they are defined for particular characteristic.

Fig. 2 Adding attributes in a PaPM function (Analyze view)

Fig. 3 Displaying attributes in a PaPM function (Analyze view)

Just like display attributes, navigational attributes defined in SAP BW can also be used in the same way (through Analyze view) in PaPM. In addition to this functionality, user can add the navigational attributes to Model BW function. Since PaPM Model BW function has two sources: Environment / Business Warehouse, let me explain to you the difference with the behavior when adding navigational attributes.

In case of Model BW function, Environment as Model BW source: all the navigational attributes for main characteristic will be available to the functions that will use Model BW as input function. The flag Navigational attributes on has to be checked in the Model BW.

Fig. 4 Switching on “navigational attributes” in Model BW/Environment source

After activation all the navigational attributes are added to function definition:

Fig.5 Model BW/Environment source definition with navigational attributes after activation

In case of Model BW function, Business Warehouse as Model BW source: only navigational attributes with checkbox Use navigational attributes in extraction switch on will be visible in PaPM function definition (ADSO defined in SAP HANA BW Modeling Tools).

Fig.6 Switching on “Use navigational attributes in extraction” in SAP HANA BW aDSO

Only navigational attributes marked as Use navigational attributes in extraction are added to function definition:

Fig.7 Model BW/Business Warehouse source definition with navigational attributes after activation

2. Using navigational attributes from “Model BW” in SAP PaPM.

As mentioned before, when a navigational attribute is populated in Model BW function, it could be used by the succeeding function that uses Model BW as input function. This means that navigational attributes behave like ordinary characteristic (field) if added as an additional field and hence can be used for filtering or selection criteria.

Fig.8 Model BW as a source for View function definition with navigational attributes used for filtering data

To oppose though to my recent statement above, navigational attributes is not possible to be used directly if the succeeding function of the Model BW is a Query. To be able to use navigational attributes in Query, the modeler needs to do a few additional steps. One way to do it is to use the Model BW as input of a View function (see Figure 8) then right after add the navigational attribute as additional field. Based on such defined view function, navigational attributes are available for a query function definition and can be used further for reporting purposes.

Tip: View function used as an input parameter for query function definition must be marked as “executable”.

Fig.9 Query function definition with navigational attributes used

Since SAP HANA BW Modeling Tools within definition of new objects (objects that came into BW world with BW/HANA and BW4/HANA like aDSO and Composite Providers), it is possible to define Transitive Attribute. Transitive attribute is a navigational attribute of a navigational attribute. Example, if A has B as a navigational attribute and further, B has C as it’s navigational attribute then C is called a Transitive Attribute for A.

In SAP PaPM, Transitive Attribute behaves and can be used the same way like an ordinary navigational as described in the earlier part of this article.

Last but not least before I close this blog post, I promised to discuss about attributes of InfoObject but you may have a question like What if I do not want to use InfoObject or BW? Can I still make use of Attributes?

Yes, Characteristic and its attributes are also possible to be created from SAP PaPM interface as Environmental fields with attributes assigned to it by defining a new field and assign it then to the main characteristic as an attribute. Maintaining master data for main characteristic and its attributes is also done from SAP PaPM as you can see in Fig.10

Fig.10 Assignment of attributes to environmental fields (main field)

Please take note that they work only as display attributes in Analyze view. You may check Attributes – quick and simple overview section for more information on how to use attributes in Analyze screen.

I hope this writing helps you in understanding the connection of PaPM with SAP BW with respect to Attributes so that you would leverage it to maximize its use for your PaPM data presentation, filtering data or report management. As mentioned earlier – time dependency for attributes and usage of it is to be covered in the next blog “Using time dependent attributes in SAP PaPM”. Stay tuned!

Annotation:

If you are familiar with BW Modeling Tools and SAP BW itself and you want to extend your knowledge in PaPM, fell free to read the appendix which contains more technical features of attributes of InfoObject. In this appendix I will use InfoObject YBW_CH095 – Customer, with display attribute YBW_CH011 – Customer name.

Appendix: Using Navigational Attributes – characteristic with display attributes usage

We can also use the BW characteristic with only display attributes defined (in PaPM ) for extending our PaPM modeling. When we define BW characteristic in SAP HANA studio BW modeling tools, additionally 2 external SAP HANA views may be generated:

  • Attribute view for characteristic master data
  • Analytic view for characteristic master data reporting

Fig. 1 Define BW characteristic with SAP HANA external view

Extending PaPM data modeling with display only attributes could be achieved in a couple of ways:

Direct usage characteristic with only display attributes in PaPM

  • Define “reporting” SAP HANA view for BW characteristic master data and then use it in Model View PaPM function

Fig. 2 Direct usage of BW characteristic with SAP HANA modeling

Indirect usage characteristic with only display attributes in PaPM

  • Use attribute view for SAP HANA view modeling – extension in SAP HANA calculation view by attributes view and then use such view in Model View PaPM function,
  • Use analytic view for SAP HANA view modeling – extension in SAP HANA calculation view by analytic view and then use such view in Model View PaPM function.

Fig. 3 Indirect usage of BW characteristic with SAP HANA modeling

In both cases (direct and indirect) usage of display attributes in PaPM there is a possibility to use such display attributes in filtering for the succeeded function of model view function.

Fig. 4 Filtering data in PaPM using display attribute of main BW characteristic

Using BW characteristic with only display attributes in PaPM is always possible in a query, Analyze of any function with the main characteristic “inside” (in definition).

Fig. 5 Adding display attribute to Analyze of PaPM function

Fig. 6 Display attribute to Analyze of PaPM function

Rating: 0 / 5 (0 votes)

The post Using SAP BW characteristic attributes in SAP PaPM appeared first on ERP Q&A.

]]>
https://www.erpqna.com/using-sap-bw-characteristic-attributes-in-sap-papm/feed/ 0 36226
End to end XS Application development in hana studio https://www.erpqna.com/end-to-end-xs-application-development-in-hana-studio/ https://www.erpqna.com/end-to-end-xs-application-development-in-hana-studio/#respond Fri, 17 Jul 2020 10:27:42 +0000 https://www.erpqna.com/?p=33648 In this blog we are going to implement an end to end sap hana xs application by using hana studio. Introduction Hana Studio is the best development environment to implement end to end application development i.e. Front-end(UI) + Back-end(Server-side Logic + Database stuffs). In this blog we are going to create two employee details custom […]

The post End to end XS Application development in hana studio appeared first on ERP Q&A.

]]>
In this blog we are going to implement an end to end sap hana xs application by using hana studio.

Introduction

Hana Studio is the best development environment to implement end to end application development i.e. Front-end(UI) + Back-end(Server-side Logic + Database stuffs). In this blog we are going to create two employee details custom tables and use those tables in calculation view to join and get the output results. After that we are going to use xsodata and xsjs service to expose view data into front-end application. XSJS is free flow process, we can write our own server-side java-script code to implement business logic.

Also Read: SAP HANAIMP 16 Certification Preparation Guide

Step 1:- First we need a server connection to implement back-end stuff. Add a system in Systems perspective.

Step 2:- Click on NEW -> XS Project

Step 3:- Provide the Project name and click on Next.

Step 4:- Select Project Workspace and check Add Project Folder as Subpackage and click on Next.

Step 5:- Select .xsaccess and .xsapp check boxes and click on Finish.

Step 6:- Project is created with below Folder structure in Project Explorer.

.xsapp file is created empty. there is no default code is generated during file creation, .xsaccess file is created with following code.

{
     "exposed" : true,  
                  
     "authentication" :                                            
            {
               "method": "Form"   
            },
  
     "cache_control" : "must-revalidate", 

     "cors" :                      
            {
             "enabled" : false
            }, 
                     
     "enable_etags" : false,

     "force_ssl" : false,
     
     "prevent_xsrf" : true
}

Step 7 :- Create two custom tables and use those tables into calculation view.

Step 8 :- Click on New->Calculation View.

Step 9 :– Provide Name, Select Type as Graphical, Data Category as Dimension and click on Finish.

Step 10 :- Design calculation view to join two tables and get the result. To see the output right click on Semantics and select Data Preview.

Step 11 :- Output results is ready. Now we need to expose this data to front-end application by using xsodata/xsjs services.

Step 12 :- Right click on Project (Sample_App) select New->File.

Follow the Step 12. create MyEmp.xsjs file with below code. In MyEmp.xsjs file i am going to expose department wise employee count. It return the single Object.

/*----------------------------------------------------------------------------------------------------------------
Purpose: Service Side Java Script
----------------------------------------------------------------------------------------------------------------*/

function Employee_Count(){

	var sqlstmt;
	var sqlstmt2;
	var conn;
	conn = $.db.getConnection();
	var oUser = $.session.getUsername();

	sqlstmt = "SELECT COUNT (DISTINCT \"EMPID\") FROM \"Schema Name\".\"Sample_App/MyFirstView\" WHERE 
                   DEPARTMENT IN ('ERP Technical(AD)')";
	sqlstmt2 = "SELECT COUNT (DISTINCT \"EMPID\") FROM \"Schema Name\".\"Sample_App/MyFirstView\" WHERE 
                   DEPARTMENT IN ('ERP Technical(UX)')";

	var num = 0;
	var num2 = 0;
	var outputCount = 0;
	var outputCount2 = 0;

	var pstmt = null;
	var pstmt2 = null;
	var rs = null;
	var rs2 = null;
	try {
		pstmt = conn.prepareStatement( sqlstmt );	
		$.trace.fatal( sqlstmt );
		rs = pstmt.executeQuery();
		while ( rs.next()) {
			num = Number(rs.getString(1));
			}
		rs.close();
		pstmt.close();

	} catch ( e ) {
		if ( rs !== null ) {
			rs.close();
		}
		if ( pstmt !== null ) {
			pstmt.close();
		}
		$.trace.fatal( e );
	}
	
	try {
		pstmt2 = conn.prepareStatement( sqlstmt2 );	
		$.trace.fatal( sqlstmt2 );
		rs2 = pstmt2.executeQuery();
		while ( rs2.next()) {
			num2 = Number(rs2.getString(1));
			}
		rs2.close();
		pstmt2.close();

	} catch ( e ) {
		if ( rs2 !== null ) {
			rs2.close();
		}
		if ( pstmt2 !== null ) {
			pstmt2.close();
		}
		$.trace.fatal( e );
	}

	var body = {};
	if (num > 0) { 
		outputCount = num;
		outputCount2 = num2;
		}
	else{ 
		outputCount = 0;
		outputCount2 = 0;
	}
	body = //JSON.stringify(
	{"d":
	{
	UserExp: outputCount2,
	ApplDev: outputCount,
	UserName:oUser
	}};
	
	return body;

    
}

$.trace.fatal( "========== BEGIN ==========" );

var result = [];

try {
	var conn = $.db.getConnection();
	result = Employee_Count();
	conn.close();
} catch ( e ) {
	$.trace.fatal( e );
}
var output = {};
output = result;
$.response.contentType = 'application/json';
$.response.setBody( JSON.stringify( output ) );
$.trace.fatal( "=========== END ===========" );

Follow the Step 12 create MyService.xsodata to fetch data from database objects and expose to UI. In MyService.xsodata i am going to expose employee details Emp_Details2 is EntitySet.

service { 
"Schema Name"."Sample_App/MyFirstView" as "Emp_Details2" keys("EMPID");
}
annotations {
     enable OData4SAP;
}

Step 13 :- Create the UI folder with following structure. In my example i have used third party library(AmCharts) for data visualization.

Step 14 :- Use the above xsodata and xsjs services in front-end application.

xml view code:

<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"
	xmlns="sap.m" xmlns:table="sap.ui.table" xmlns:comn="sap.ui.commons"
	xmlns:smartFilterBar="sap.ui.comp.smartfilterbar" xmlns:smartTable="sap.ui.comp.smarttable"
	xmlns:f="sap.f" displayBlock="true"
	controllerName="Sample_App.Table_GUI.view.Table_Grouping"
	xmlns:html="http://www.w3.org/1999/xhtml"
	xmlns:customData="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1">
	<f:DynamicPage id="oDynamicPageId">
		<f:title>
			<f:DynamicPageTitle>
				<f:heading>
					<Title text="ERP Technical Employee Info" />
				</f:heading>
				<f:actions>
					<ToolbarSpacer />
					<core:Icon src="sap-icon://refresh" tooltip="Logout"
						noTabStop="true" press="onLogOutPress" />
					<core:Icon id="oExeId" src="sap-icon://donut-chart"
						tooltip="Visualization" noTabStop="true" />
				</f:actions>
			</f:DynamicPageTitle>
		</f:title>
		<f:content>
			<smartTable:SmartTable id="pricequoteTable"
			 smartFilterId="smartFilterBar"
			 beforeRebindTable="beforeRebindTable"
			 enableAutoBinding="true"
				entitySet="Emp_Details2" initialise="onSmartTableInit"
				tableType="ResponsiveTable" editTogglable="true" customData:useSmartField="true" showTablePersonalisation="true"
				fieldChange="onFieldChange" useExportToExcel="true" editable="false"
				useVariantManagement="true" useTablePersonalisation="true"
				 header="Employees" width="100%" height="100%"
				class="sapUiSizeCompact">
			</smartTable:SmartTable>
		</f:content>
		<f:footer>
			<OverflowToolbar>
				<ToolbarSpacer />
				<Button type="Accept" icon="sap-icon://save" text="Save"
					press="oSubmitChanges" />
				<Button type="Reject" text="Reject" press="onReject"/>
			</OverflowToolbar>
		</f:footer>
	</f:DynamicPage>
</core:View>

controller code:

jQuery.sap.require("sap.m.MessageBox");
sap.ui.controller("Sample_App.Table_GUI.view.Table_Grouping",{
onInit: function() {
					 var sURL, oModel, oView;
					  sURL = "/Sample_App/MyService.xsodata";
					 var oModel = new sap.ui.model.odata.v2.ODataModel(sURL);
					  oModel.setDefaultBindingMode("TwoWay");
					  var oView = this.getView();
					  oView.setModel(oModel);
					  var oTable = this.getView().byId("pricequoteTable");
					  oTable.setInitiallyVisibleFields("EMPID,EMP_NAME,DESIGNATION,MOBILE,ADDRESS,DEPARTMENT");		    		
					this.oRouter = sap.ui.core.routing.Router.getRouter("appRouter");
					var oPage = this.getView().byId("oDynamicPageId");
					oPage.setShowFooter(!oPage.getShowFooter());
			},

			onSmartTableInit : function(oEvent){
			var oTable = oEvent.getSource().setShowRowCount(true);
			
			},
                        onAfterRendering : function(){
			var oTable = this.getView().byId("pricequoteTable");
				
				if(!oTable){
					
					 var oPersButton = oTable._oTablePersonalisationButton.attachPress(function(){
							
							var oPersController = oTable._oPersController;
					          var oPersDialog = oPersController._oDialog.fireReset();
							
						});
				}
				        
				this.getView().byId("oExeId").attachPress(function(){
					
					sURL = "/Sample_App/MyEmp.xsjs";
					 var oModel = new sap.ui.model.odata.v2.ODataModel(sURL);
					 var uxArr = 0;
					 var adArr = 0;
					 $.get(sURL, function(data, status){
					adArr = data.d.ApplDev;
					uxArr = data.d.UserExp;
					var oPanel = new sap.m.Panel({ height:"500px", width:"100%"});
					var oId = oPanel.sId;
					var chart = AmCharts.makeChart(oId,{
					    "type": "pie",
					    "theme": "light",
					    "innerRadius": "40%",
					    "gradientRatio": [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, 0, 0.1, 0.2, 0.1, 0, -0.2, -0.5],
					    "dataProvider": [{
					        "Department": "ERP Technical(UX)",
					        "Count": uxArr
					    },
					    {
					        "Department": "ERP Technical(AD)",
					        "Count": adArr
					    }],
					    "balloonText": "[[value]]",
					    "valueField": "Count",
					    "titleField": "Department",
					    "balloon": {
					        "drop": true,
					        "adjustBorderColor": false,
					        "color": "#FFFFFF",
					        "fontSize": 16
					    },
					    "export": {
					        "enabled": true
					    }
					});
						this.resizableDialog = new sap.m.Dialog({
							title: 'Employee Details Visualization',
							contentWidth: "100%",
							contentHeight: "100%",
							resizable: true,
							draggable : true,
							content: oPanel,
							beginButton: new sap.m.Button({
								text: 'Close',
								press: function () {
									oPanel.destroyContent();
									this.resizableDialog.destroy();
								}.bind(this)
							})
						});						
						this.resizableDialog.open();	
						chart.write(oId);		
//					 }});	
					 });
				});
			},
			
			oSubmitChanges : function(){
				var oTable = this.getView().byId("pricequoteTable");
				var changesFlag = this.getView().getModel().hasPendingChanges();
				if(changesFlag){
				oTable.setEditable(false);
				this.getView().getModel().submitChanges({success:function(){
					sap.m.MessageToast.show("Successfully submitted");
				}});
				}else{
					sap.m.MessageToast.show("No pending changes to submit");
				}
			},
			
			onReject:function(){
				var oTable = this.getView().byId("pricequoteTable");
				oTable.setEditable(false);
				this.getView().getModel().resetChanges();
			}
});

Here is the output: Once we click on top right corner icon(donut). Visual chart will be appear on dialog with department wise employee count.

Rating: 0 / 5 (0 votes)

The post End to end XS Application development in hana studio appeared first on ERP Q&A.

]]>
https://www.erpqna.com/end-to-end-xs-application-development-in-hana-studio/feed/ 0 33648
Looking forward for the next available value in a table without using LEAD or LAG function or LOOPING in SAP HANA https://www.erpqna.com/looking-forward-for-the-next-available-value-in-a-table-without-using-lead-or-lag-function-or-looping-in-sap-hana/ https://www.erpqna.com/looking-forward-for-the-next-available-value-in-a-table-without-using-lead-or-lag-function-or-looping-in-sap-hana/#respond Sun, 12 Jan 2020 03:38:50 +0000 https://www.erpqna.com/?p=25135 REQUIREMENT This blog is regarding the calculation of “Production Ratio” in Supply Chain Management for the monthly bucket in SAP HANA. The client wanted to see, Production Ratio of a year for each month for a particular Product, Location and Product Version combination. In my case Production Ration was calculated as (Quantity / Total Quantity […]

The post Looking forward for the next available value in a table without using LEAD or LAG function or LOOPING in SAP HANA appeared first on ERP Q&A.

]]>
REQUIREMENT

This blog is regarding the calculation of “Production Ratio” in Supply Chain Management for the monthly bucket in SAP HANA.

The client wanted to see, Production Ratio of a year for each month for a particular Product, Location and Product Version combination. In my case Production Ration was calculated as (Quantity / Total Quantity * 100) for each month. The catch is when there is no value for Quantity and Totaly Quantity in a month, then we have to look forward to the upcoming months for values.

Use Case: Reapplying the production/ transportation quota to most relevant BOM/ lane. This scenario is applicable in almost all the supply chain planning projects where you take constrained/ unconstrained supply plan and extracts production and transportation quotas for Inventory planning.

DATA and SOLUTION

Let me first introduce you with the reference table which has six columns namely PRODUCT, LOCATION, P_VERSION (PRODUCT VERSION), QTY (QUANTITY), TOTAL_QTY (TOTAL QUANTITY) and DATE.

This table contains the list of ordered quantity of a product (i.e. material) from a location (i.e. plant) for an entire year. If you look at the table, there is a zero (or null) quantity ordered in Jan. In Feb, we have ordered 10 quantity of product version 001 and 20 quantity of product version 002, so the total order quantity is 30. Similarly, we have values of ordered quantity for the rest of the months.

Now, when I say we have to look forward whenever there is a null value for QTY and TOTAl_QTY, then for Jan, we should have values from Feb (which is the first non-null value month after Jan) Hence, for Jan there will be two product versions 001 and 002, and their respective ordered quantity from Feb. Similarly, for Mar, Apr, May and June, July is the desired month to look for value.

In simple words,

  • Jan will have values from Feb. (two versions)
  • Mar, Apr, May and June will have values from July.
  • Aug and Sept will have values from Oct. (two versions)
  • Nov will have values from Dec.

To achieve this, I have used Table Function, which can be further consumed in a Calculation view to get the result.

TABLE T1 SELECTING VALUES

Select all the values from the referenced table or VDM.

T1 = Select * From BASE_TABLE;

TABLE T2 SET FLAG WHERE TOTAL_QTY IS NULL

Here, we will select only “PRODUCT”, “LOCATION”, “TOTAL_QTY” and “DATE” fields from table T1. Set FLAG as 0, where the value of “TOTAL_QTY” is NULL, else Set FLAG as 1.

T2 =  SELECT
      "PRODUCT",
      "LOCATION",
      "DATE",
      "TOTAL_QTY",
    CASE When "TOTAL_QTY" Is Null 
    Then 0 
    ELSE 1 
    END AS "FLAG" 
FROM :T1 
order by "DATE";

TABLE T3 APPLY RUNNING SUM ON FLAG

Now, apply the “Running Sum” Function on the “FLAG” column. By doing so, you would notice that the value of running sum column, i.e., “FLAG_SUM” changes whenever a non-null “TOTAL_QTY” row occurs. This will become clearer in the next step, how this would help us.

T3 = SELECT
     "PRODUCT",
     "LOCATION",
     "DATE",
     "TOTAL_QTY",
     "FLAG",
     SUM("FLAG") OVER (PARTITION BY "PRODUCT","LOCATION" ORDER BY "DATE") AS "FLAG_SUM" 
FROM :T2 
order by "DATE";

TABLE T4 APPLY ROW_NUMBER() ON FLAG_SUM

Apply ROW_NUMBER() Function on “PRODUCT”, “LOCATION”, and “FLAG_SUM” and Order By “DATE” in DESC order.

Now, if you look at the result, the “ROW_NUM” column gives the number of rows (here, months) to look forward to get the value. For example, the value for Jan is supposed to be picked from Feb. Here, Jan(1) + ROW_NUM(1) = Feb(2). Similarly, for March, April, May and June, the month to look forward for the value is July. So, March(3) + ROW_NUM(4) = July(7), and so on.

NOTE: – ROW_NUMBER() function applied on “DATE” must be in DESC order.

T4 = SELECT
     "PRODUCT",
     "LOCATION",
     "DATE",
     "TOTAL_QTY",
     "FLAG",
     "FLAG_SUM",
     ROW_NUMBER() OVER (PARTITION BY "PRODUCT","LOCATION","FLAG_SUM" ORDER BY "DATE" DESC) AS "ROW_NUM"
FROM :T3
order by "DATE";

TABLE T5 ADD NUMBER OF MONTHS TO THE DATE COLUMN

Adding the number of months to “DATE” from “ROW_NUM” column to get a new column as “DATE_NEW”, which is the desired month to look forward to the next available value (as explained above).

T5 = SELECT
     "PRODUCT",
     "LOCATION",
     "DATE",
     "TOTAL_QTY",
     "FLAG",
     "FLAG_SUM",
     "ROW_NUM",
      TO_DATE (ADD_MONTHS( "DATE","ROW_NUM")) AS "DATE_NEW" 
From :T4 
order by "DATE";

TABLE T6 LEFT OUTER JOIN ON T1 AND T5

Now, apply “Left Outer” join on table T1 and T5, keeping T1 (our base table) as LEFT and T5 (having “DATE_NEW” column) as RIGHT. By this, we will have the desired months to look for under “DATE_NEW” column for each row.

NOTE: – You might have noticed that we are having two rows for P_VERSION-001 in Feb (2019-02-01). These will be handled going forward.

T6 = select
     T1."PRODUCT",
     T1."LOCATION",
     T1."P_VERSION",
     T1."QTY",
     T1."TOTAL_QTY",
     T1."DATE",

     T5."DATE_NEW" 
	 
From :T1 AS T1 LEFT OUTER JOIN :T5 AS T5 
 on T5."PRODUCT"  = T1."PRODUCT"
AND T5."LOCATION" = T1."LOCATION" 
AND T5."DATE"     = T1."DATE" 
order by "DATE";

TABLE T7 LEFT OUTER JOIN ON T6 AND T1

Apply “Left Outer” join on table T6 and T1, keeping T6 as LEFT and T1 (our base table) as RIGHT. By this, we will have the desired values of “P_VERSION”, “QTY” and “TOTAL_QTY” under “P_VERSION1”, “QTY1” and “TOTAL_QTY1” columns, respectively, for each row.

NOTE: – As mentioned above, don’t worry about the duplicate entries as we are going to handle them soon.

T7 = SELECT	  
     T6."PRODUCT",
     T6."LOCATION",
     T6."P_VERSION",
     T6."QTY",
     T6."TOTAL_QTY",
     T6."DATE",

     T1."P_VERSION" AS "P_VERSION1",
     T1."QTY" AS "QTY1",
     T1."TOTAL_QTY" AS "TOTAL_QTY1"
	  
FROM :T6 AS T6 LEFT OUTER JOIN :T1 AS T1 
 on T1."PRODUCT"  = T6."PRODUCT" 
AND T1."LOCATION" = T6."LOCATION" 
AND T1."DATE"     = T6."DATE_NEW"
order by "DATE";

OUTPUT BUILD USING T7

Select the required fields “PRODUCT”, “LOCATION”, “P_VERSION”, “QTY”, “TOTAL_QTY” and “DATE”.

“SELECT DISTINCT” will remove the duplicate entries (as mentioned above).

Now, if we have a null value for “P_VERSION”, only then “P_VERSION1” will be picked up. Else, “P_VERSION” will remain as it is. Similar will be the case for “QTY” and “TOTAL_QTY”. This will give us our final output.

var_out =
   SELECT
	 DISTINCT
	 "PRODUCT",
	 "LOCATION",
	 
	 CASE When "P_VERSION" Is Null 
	 Then "P_VERSION1" 
	 ELSE "P_VERSION" 
	 END AS "P_VERSION",
	 
	 CASE When "QTY" Is Null 
	 Then "QTY1" 
	 ELSE "QTY" 
	 END AS "QTY",
	
	 CASE When "TOTAL_QTY" Is Null 
	 Then "TOTAL_QTY1" 
	 ELSE "TOTAL_QTY" 
	 END AS "TOTAL_QTY",
	 
	 "DATE"
	  
FROM :T7
order by "DATE",
         "P_VERSION";

By this, we are having the values of Quantity and Total Quantity for each month which will help us in calculating our Production Ratio for the monthly bucket.

Rating: 0 / 5 (0 votes)

The post Looking forward for the next available value in a table without using LEAD or LAG function or LOOPING in SAP HANA appeared first on ERP Q&A.

]]>
https://www.erpqna.com/looking-forward-for-the-next-available-value-in-a-table-without-using-lead-or-lag-function-or-looping-in-sap-hana/feed/ 0 25135
Sum of Multiple Rows based on a condition (validation) without using LOOP in SAP HANA https://www.erpqna.com/sum-of-multiple-rows-based-on-a-condition-validation-without-using-loop-in-sap-hana/ https://www.erpqna.com/sum-of-multiple-rows-based-on-a-condition-validation-without-using-loop-in-sap-hana/#respond Wed, 01 Jan 2020 08:43:28 +0000 https://www.erpqna.com/?p=24618 REQUIREMENT This blog post is regarding the validation of “Production Ratio” in Supply Chain Management for the monthly bucket in SAP HANA. Read More: SAP HANATEC 12 Certification Preparation Guide The client wanted to see “Production Ratio” of each month for a particular Product, Location and Product Version combination with validation. In my case, when […]

The post Sum of Multiple Rows based on a condition (validation) without using LOOP in SAP HANA appeared first on ERP Q&A.

]]>
REQUIREMENT

This blog post is regarding the validation of “Production Ratio” in Supply Chain Management for the monthly bucket in SAP HANA.

Read More: SAP HANATEC 12 Certification Preparation Guide

The client wanted to see “Production Ratio” of each month for a particular Product, Location and Product Version combination with validation. In my case, when I say validation, it means that “Production Ratio” was compared with a threshold value to decide whether it will remain as it is or gets added to the next valid “Production Ratio” of the same month (Production Ratio should be greater than or equal to the threshold value). Let us take the threshold value as 5, and move forward to understand the various scenarios below.

Case 1:-

In this case, we are having three different versions of a “PRODUCT” (i.e. material) in a particular month, i.e., 003, 004 and 005. Here, only one version (005) has a “PRATIO” (Production Ratio) 6, which is greater than 5 (threshold value). So, in this case, “PRATIO” value of versions 003 and 004 i.e., 1 and 2 respectively, will get added to the “PRATIO” value of version 005, and their “FINAL_PRATIO” value becomes 0 (as shown below).

Case 2:-

In this case, we are having three different versions of a “PRODUCT” in a particular month, i.e., 001, 002 and 003, among which two versions, 002 and 003 have a “PRATIO” (Production Ratio) greater than our threshold value(5). So in this case, “PRATIO” value of version 001, i.e., 1 will get added to the highest “PRATIO” value, i.e., of version 003 which is 8 (as shown below).

Case 3:-

In this case, we are having three different versions of a “PRODUCT” in a particular month, i.e., 001, 002 and 003, among which two versions, 002 and 003 have a “PRATIO” (Production Ratio) greater than our threshold value (5), similar to the above scenario. But, “PRATIO” value of versions 002 and 003 are the same (7), So in this case, “PRATIO” value of version 001 will get added to the latest version, i.e., 003 (As we can’t decide highest among them).

NOTE: – When we can’t decide the highest Production Ratio, then we consider the latest Product Version as valid.

Case 4:-

In this case, we are having three different versions of a “PRODUCT” in a particular month, i.e., 001, 002 and 003, among which all have “PRATIO” (Production Ratio) values less than our threshold value (5). So, in this case, “PRATIO” value of versions 001 and 002 will get added to the “PRATIO” value of 003 (having the highest PRATIO value among them).

Case 5:-

In this case, we are having three different versions of a “PRODUCT” in a particular month, i.e., 002, 003 and 004, among which all have “PRATIO” (Production Ratio) values are less than our threshold value (5). But, “PRATIO” value of all versions are the same (1). So, in this case, “PRATIO” value of versions 002 and 003 will get added to the “PRATIO” value of 004 (latest “PRODUCT VERSION” among them).

Case 6:-

In this case, we are having two different versions of a “PRODUCT” in a particular month, i.e. 002 and 003, among which both have “PRATIO” (Production Ratio) value greater than our threshold value (5). So, in this case, the values will remain as it is.

Case 7:-

In this case, we are having only one version of a “PRODUCT” in a particular month, i.e., 001 in the month of AUG and 002, in the month of SEPT. So, whenever we are having only one version in a month, we have to leave it as it is without even validating it with our threshold value.

To sum up the above scenarios (for a single month):-

  • Production Ratio greater than the threshold value is considered the valid one. E.g.:- Case 1
  • If more than one Production Ratio is greater than the threshold value, then the highest one among them is the valid one. E.g.:- Case 2
  • If more than one Production Ratio is greater than the threshold value, and we can’t decide highest among them, then Production Ratio of the latest version is considered the valid one. E.g.:- Case 3
  • If all Production Ratio is less than the threshold value, then the highest among them is the valid one. E.g.: – Case 4
  • If all Production Ratios are less than the threshold value, and we can’t decide highest among them, then Production Ratio of the latest version is considered the valid one. E.g.:- Case 5
  • If all Production Ratios are greater than the threshold value, then the values will remain the same. E.g.:- Case 6
  • If we have only one Production Ratio in a month, then the value will remain the same. E.g.: – Case 7

Use Case / Business Scenario: Reapplying the production/ transportation quota to the most relevant BOM/ lane. This scenario is applicable in almost all the supply chain planning projects, where you take constrained/ unconstrained supply plan and extract production and transportation quotas for Inventory planning.

DATA and SOLUTION

Our reference table has five columns namely “PRODUCT”, “LOCATION”, “DATE”, “P_VERSION” (PRODUCT VERSION) and “PRATIO” (Production Ratio).

This table contains the values of Production Ratio for various versions of a Product (i.e. material) from a location (i.e. plant) in a particular month, where we have to apply our validation rules, to sum up, multiple rows.

To achieve this, I have used Table Function, which can be further consumed in a Calculation view to get the result.

TABLE T1 SELECT VALUES

Select all the values from the referenced table or VDM.

T1 = Select * From BASE_TABLE;

TABLE T2 SELECT MONTHS HAVING MULTIPLE VALUES

Select the months having multiple Product versions. By this, AUG and SEPT months will be left out, as these months have only one version.

T2 = select
       A."PRODUCT",
       A."LOCATION",
       A."DATE",
       A."P_VERSION",
       A."PRATIO" 
from :T1 as A inner join
       (select
	 "PRODUCT",
	 "LOCATION",
	 "DATE",
	 count(*) 
	from :T1 
	group by "PRODUCT","LOCATION","DATE" having count(*) > 1) AS B 
 on A."PRODUCT"  = B."PRODUCT" 
and A."LOCATION" = B."LOCATION" 
and A."DATE"     = B."DATE" 
order by "DATE",
         "P_VERSION",
         "PRATIO";

TABLE T3 SET FLAG WHERE PRODUCTION RATIO IS GREATER THAN THRESHOLD VALUE

Select values of table T2 and set FLAG as N, where the value of “PRATIO” (Production Ratio) is greater than the threshold value (5). Else, set FLAG as Y(less than the threshold value).

T3 = select
	 *,	 
  CASE When "PRATIO" >= 5 
  Then 'N' 
  ELSE 'Y' 
  END AS "FLAG" 
from :T2 
order by "DATE",
         "P_VERSION",
         "PRATIO";

TABLE T4 SET PRATIO AS 0 WHERE FLAG IS ‘N’

Set value of “PRATIO” as 0, where FLAG is N. And for Y, the value will remain as it is, in a separate column “PRATIO_NEW”.

T4 = SELECT
	 *,
  case when "FLAG" = 'Y' 
  then "PRATIO" 
  else 0 
  end as "PRATIO_NEW" 
from :T3 
order by "DATE",
         "P_VERSION",
         "PRATIO";

TABLE T5 RUNNING SUM ON “PRATIO_NEW” AND MAX OF “PRATIO”

Now, apply the “Running Sum” Function on the “PRATIO_NEW” column and create a new column as “PRATIO_SUM”. Create one more new column “MAX_VALUE”, which shows the highest value “PRATIO” of the particular month. By doing so, you would notice that we are having 3 as the highest value for the month of JAN (2019-01-01) under “MAX_VALUE” column.

NOTE: – “MAX_VALUE” will help us in that scenario where we need the highest value of “PRATIO” in a particular month.

T5 = SELECT
      *,
     SUM("PRATIO_NEW") OVER (PARTITION BY "PRODUCT","LOCATION","DATE" ORDER BY "DATE") AS "PRATIO_SUM",
     MAX("PRATIO")  OVER (PARTITION BY "PRODUCT","LOCATION",
"DATE" ORDER BY "DATE") AS "MAX_VALUE"
from :T4 
order by "DATE",
         "P_VERSION",
         "PRATIO";

TABLE T6 APPLY ROW_NUMBER() AND CREATE A COLUMN “FINAL_SUM”

Apply ROW_NUMBER() Function on “PRODUCT”, “LOCATION”, and “DATE”, with Order By “DATE”, “PRATIO”. Moving ahead, you will notice how this helps us in getting the latest Product Version.

Create a new column “FINAL_SUM” by applying the formula (“MAX_VALUE” + “PRATIO_SUM”) – “PRATIO_NEW”. Moving ahead, you will notice how this helps us in getting the correct value of Final Pratio.

TABLE T7 APPLY MAX() ON ROW_NUM

Now, apply the “MAX” Function on the “ROW_NUM” column. By doing so, we will have the highest value of ROW_NUM for any particular month under “MAX_ROW” column. Down the line, this is going to help us in getting the latest Product Version.

T7 = SELECT
     *,
     MAX("ROW_NUM") OVER (PARTITION BY "PRODUCT","LOCATION","DATE") AS "MAX_ROW"	 
from :T6 
order by "DATE",
         "P_VERSION",
         "PRATIO";

TABLE T8_Y VALUES HAVING FLAG ‘Y’

Select values from Table 7 where “FLAG” is ‘Y’.

T8_Y = SELECT
	 * 
   FROM :T7 
WHERE "FLAG" = 'Y';

TABLE T8_N VALUES HAVING FLAG ‘N’

Select values from Table 7 where “FLAG” is ‘N’.

T8_N = SELECT
	 * 
   FROM :T7 
WHERE "FLAG" = 'N';

Before going further, I would like to explain the reason we have divided the data set based on the “FLAG” is because we are going to implement various conditions on the basis of the “FLAG”.

Let us try to understand with the help of above image having colour coding.

For “FLAG” = ‘Y’,

For “FLAG” = ‘N’,

TABLE T9_Y

Select “PRODUCT”, “LOCATION”, “DATE”, “P_VERSION” and “PRATIO”. Create a new column “PRATIO_FINAL” with condition – When “MAX_ROW” = “ROW_NUM”, “FINAL_SUM” = “PRATIO_SUM” and “MAX_VALUE” = “PRATIO_NEW” then, “FINAL_SUM” will be “PRATIO_FINAL”, else, “PRATIO_FINAL” will be 0.

T9_Y = SELECT
	 "PRODUCT",
	 "LOCATION",
	 "DATE",
	 "P_VERSION",
	 "PRATIO",
 CASE When "MAX_ROW" = "ROW_NUM" 
     AND "FINAL_SUM" = "PRATIO_SUM" 
     AND "MAX_VALUE" = "PRATIO_NEW" 
 Then "FINAL_SUM" 
 ELSE 0 
 END AS "PRATIO_FINAL" 
	FROM :T8_Y 
	order by "DATE",
	         "P_VERSION",
	         "PRATIO";

TABLE T9_N

Select “PRODUCT”, “LOCATION”, “DATE”, “P_VERSION” and “PRATIO”. Create a new column “PRATIO_FINAL” with condition- When “MAX_ROW” = “ROW_NUM” and “MAX_VALUE” = “PRATIO” then, “FINAL_SUM” will be “PRATIO_FINAL”, else, “PRATIO” will be “PRATIO_FINAL”.

T9_N = SELECT
       "PRODUCT",
       "LOCATION",
       "DATE",
       "P_VERSION",
       "PRATIO",
 CASE When "MAX_ROW" = "ROW_NUM" 
       AND "MAX_VALUE" = "PRATIO" 
 Then "FINAL_SUM" 
 ELSE "PRATIO" 
 END AS "PRATIO_FINAL" 
	FROM :T8_N 
	order by "DATE",
	         "P_VERSION",
	         "PRATIO";

TABLE T9 (T9_Y + T9_N)

Apply UNION ALL on tables T9_Y and T9_N and create a new table T9.

T9 = 
SELECT * FROM :T9_Y	
      UNION ALL
SELECT * FROM :T9_N
   order by "DATE",
            "P_VERSION",
            "PRATIO";

TABLE T10

Now, apply “Left Outer” join on table T1 and T9, keeping T1 (our base table) as LEFT and T9 (having “PRATIO_FINAL” column) as RIGHT. By this, we will have all the fields from table T1 along with our desired field “PRATIO_FINAL” from table T9.

You might have noticed that two rows AUG (2019-08-01) and SEPT (2019-09-01) having null values for “PRATIO_FINAL”, as these months were not present in the table T9. We will handle this in our next and final step.

“SELECT DISTINCT” will remove the duplicate entries.

T10 = SELECT
	 Distinct T1.*,
	 T9."PRATIO_FINAL" 
from :T1 AS T1 
LEFT OUTER JOIN :T9 as T9 
 on T1."PRODUCT"  = T9."PRODUCT" 
AND T1."LOCATION" = T9."LOCATION" 
AND T1."DATE"      = T9."DATE" 
AND T1."P_VERSION" = T9."P_VERSION" 
AND T1."PRATIO"    = T9."PRATIO" 
order by "DATE",
         "P_VERSION",
         "PRATIO";

FINAL TABLE

Select the required fields “PRODUCT”, “LOCATION”, “DATE”, “P_VERSION” and “PRATIO” from table T10.

Now, if we have a null value for “PRATIO_FINAL”, only then “PRATIO” will be picked up as “PRATIO_FINAL”. Else, “PRATIO_FINAL” will remain as it is. This will give us our final output.

VAR_OUT = 		 
     SELECT
       "PRODUCT",
       "LOCATION",
       "DATE",
       "P_VERSION",
       "PRATIO",
	
CASE When "PRATIO_FINAL" IS NULL 
Then "PRATIO" 
ELSE "PRATIO_FINAL" 
END AS "PRATIO_FINAL"

FROM :T10 
order by "DATE",
         "P_VERSION",
         "PRATIO";

CONCLUSION

Now, once we are having the final values of “PRATIO” as “PRATIO_FINAL” for each month, we can simply use this Table Function as a data source in a Calculation View with the help of a Projection to see the result. By this, we were able to distribute the production/ transportation quota to the most relevant BOM/ lane.

CODE:-

FUNCTION "XXXXX"."YY.PPPPP::TF_PRATIO_VALIDATION_TEST" ( ) 
       RETURNS TABLE (
                      "PRODUCT" NVARCHAR(10),
                      "LOCATION" NVARCHAR(5),
                      "DATE" NVARCHAR(10),
                      "P_VERSION" NVARCHAR(5),
                      "PRATIO" DECIMAL(12,3),
                      "PRATIO_FINAL" DECIMAL(12,3)
                      )                      
       LANGUAGE SQLSCRIPT
       SQL SECURITY INVOKER AS
BEGIN
/***************************** 
       Write your function logic
*****************************/
T1 = Select * from BASE_TABLE;

T2 = select
       A."PRODUCT",
       A."LOCATION",
       A."DATE",
       A."P_VERSION",
       A."PRATIO" 
from :T1 as A 
inner join (select
       "PRODUCT",
       "LOCATION",
       "DATE",
       count(*) 
       from :T1 
       group by "PRODUCT",
       "LOCATION",
       "DATE" having count(*) > 1) AS B 
 on A."PRODUCT"  = B."PRODUCT" 
and A."LOCATION" = B."LOCATION" 
and A."DATE"     = B."DATE" 
order by "DATE",
         "P_VERSION",
         "PRATIO";
              
T3 = select
       *,    
  CASE When "PRATIO" < 5 
  Then 'Y' 
  ELSE 'N' 
  END AS "FLAG" 
from :T2 
order by "DATE",
         "P_VERSION",
         "PRATIO";       
              
T4 = SELECT
       *,
  case when "FLAG" = 'Y' 
  then "PRATIO" 
  else 0 
  end as "PRATIO_NEW" 
from :T3 
order by "DATE",
         "P_VERSION",
         "PRATIO";

T5 = SELECT
       *,
       SUM("PRATIO_NEW") OVER (PARTITION BY "PRODUCT","LOCATION","DATE" ORDER BY "DATE") AS "PRATIO_SUM",
       MAX("PRATIO")  OVER (PARTITION BY "PRODUCT","LOCATION","DATE" ORDER BY "DATE") AS "MAX_VALUE"
from :T4 
order by "DATE",
         "P_VERSION",
         "PRATIO";             

T6 = SELECT
     *,
       ("MAX_VALUE" + "PRATIO_SUM") - "PRATIO_NEW" as "FINAL_SUM",
       ROW_NUMBER() OVER (PARTITION BY "PRODUCT","LOCATION","DATE" ORDER BY "DATE","PRATIO" ) AS "ROW_NUM"     
from :T5 
order by "DATE",
         "P_VERSION",
         "PRATIO";       
              
T7 = SELECT
     *,
       MAX("ROW_NUM") OVER (PARTITION BY "PRODUCT","LOCATION","DATE") AS "MAX_ROW"      
from :T6 
order by "DATE",
         "P_VERSION",
         "PRATIO"; 
      
T8_Y = SELECT
       * 
FROM :T7 
WHERE "FLAG" = 'Y';

T8_N = SELECT
       * 
FROM :T7 
WHERE "FLAG" = 'N';        
               
               
T9_Y = SELECT
       "PRODUCT",
       "LOCATION",
       "DATE",
       "P_VERSION",
       "PRATIO",
CASE When "MAX_ROW" = "ROW_NUM" 
     AND "FINAL_SUM" = "PRATIO_SUM" 
     AND "MAX_VALUE" = "PRATIO_NEW" 
 Then "FINAL_SUM" 
 ELSE 0 
 END AS "PRATIO_FINAL" 
       FROM :T8_Y 
       order by "DATE",
                "P_VERSION",
                "PRATIO";

T9_N = SELECT
       "PRODUCT",
       "LOCATION",
       "DATE",
       "P_VERSION",
       "PRATIO",
CASE When "MAX_ROW" = "ROW_NUM" 
        AND "MAX_VALUE" = "PRATIO" 
 Then "FINAL_SUM" 
 ELSE "PRATIO" 
 END AS "PRATIO_FINAL" 
       FROM :T8_N 
       order by "DATE",
                "P_VERSION",
                "PRATIO";   
T9 =           
SELECT * FROM :T9_Y  
      UNION ALL
SELECT * FROM :T9_N
   order by "DATE",
            "P_VERSION",
            "PRATIO";          
               
T10 = SELECT
       distinct T1.*,
       T9."PRATIO_FINAL" 
from :T1 AS T1 
LEFT OUTER JOIN :T9 as T9 
 on T1."PRODUCT"  = T9."PRODUCT" 
AND T1."LOCATION" = T9."LOCATION" 
AND T1."DATE"      = T9."DATE" 
AND T1."P_VERSION" = T9."P_VERSION" 
AND T1."PRATIO"    = T9."PRATIO" 
order by "DATE",
         "P_VERSION",
         "PRATIO";       
              
VAR_OUT =             
SELECT
       "PRODUCT",
       "LOCATION",
       "DATE",
       "P_VERSION",
       "PRATIO",
       
CASE When "PRATIO_FINAL" IS NULL 
Then "PRATIO" 
ELSE "PRATIO_FINAL" 
END AS "PRATIO_FINAL"
       
FROM :T10 
order by "DATE",
         "P_VERSION",
         "PRATIO";
              
return :var_out;

END;
Rating: 0 / 5 (0 votes)

The post Sum of Multiple Rows based on a condition (validation) without using LOOP in SAP HANA appeared first on ERP Q&A.

]]>
https://www.erpqna.com/sum-of-multiple-rows-based-on-a-condition-validation-without-using-loop-in-sap-hana/feed/ 0 24618