Skip to Content
Technical Articles
Author's profile photo Sagar Sheokand

Simplest Way to Generate a Custom Hierarchy in BW – Without a DataSource & Using Master Data (Attribute/s) Only.

Update 12/12/2020: Code for following advanced cases added:

  • Multiple Hierarchies
  • Time Dependent Hierarchies
  • Multilevel Hierarchies
  • Duplicate Leaf Nodes

Prerequisites: You need some understanding of both, ABAP and how hierarchy in BW works, to be able to write/alter the code involved.

1. Introduction:

Lately, I was asked to design a solution that generates a custom hierarchy for an InfoObject. InfoObject to be used is 0CUSTOMER and 0CUSTOMER has an attribute – ZCCST_GRP (Customer Group). The hierarchy must use various customer groups as text nodes and under those nodes must lay our customers. Essentially a tree structure where all the customers are clubbed under their parent customer groups.

The only object that we will need to achieve this is a self-transformation on 0CUSTOMER (from ATTR to HIERARCHY) (and an expert routine on that transformation). No hierarchy data source is required!

The picture below shows the required result:Expected Output - ABC, TEST1, NE*****, TEST2, TEST3, and TEXT 
are customer groups and they have their respective customers 
underneath them.

 

All the existing solutions tell you to generate an export DataSource on 0CUSTOMER and write a Customer Exit/BAdI for that DataSource and whatnot. That certainly isn’t required anymore with the new Hierarchy framework (BW 7.3 & above) and this solution seems to be the neatest.

2. System Details & Requirements:

I’m working on BW 7.5 but this should work on any system above 7.3. (Irrespective of this blog, my deepest sympathies if you’re below 7.3).

3. Transformation & Routine:

Create a transformation for the hierarchy subtype of 0CUSTOMER.

In source, select Object Type = InfoObject, Name = 0CUSTOMER, and 
Subtype = Attributes.Once the transformation is created, create an expert routine for it. 
From menu bar select: Edit -> Routines -> Expert Routine.

 

Now, all we need to do is write the code in the expert routine and our solution will be complete. But before that, one must understand that the transformations for hierarchies are segmented by default. These segments will be utilized in the expert routine and hence, we need a brief understanding of them. If you already do understand this, skip step 4, and jump to the code.

4. Segments in Hierarchy Transformations:

There are 5 segments in total. You can view them just next to the rule group button.

See the picture below for reference:Segments in a Hierarchy Transformation. Highlighted are the ones that 
are mandatory.

 

Out of the 5 segments, only two are mandatory – Hierarchy Header & Hierarchy Structure. Hierarchy Header is mandatory only if you want to generate multiple hierarchies. It can be excluded for a single hierarchy. In this example, I’m only showcasing a single hierarchy but still have used Hierarchy Header for future-proofing the code. I would recommend using it even for a single hierarchy. I have also used Texts for Text Node to enter the text for the text nodes. This isn’t mandatory at all.

Now, just like in a normal transformation we have a result_package in the end routine; here, all 5 target segments have their own result_package called, respectively, result_package_1, result_package_2, result_package_3, result_package_4 & result_package_6 (yes, there is no result_package_5).

So we’ll need to fill these result_packages manually as it is an expert routine and since we want to use three segments, we’ll have to populate the result packages associated with all three of them. They are listed as below:

  • Hierarchy Header – result_package_1 <- Mandatory for multiple hierarchies. Recommended to be used always.
  • Hierarchy Structure – result_package_3 <- Mandatory. This is where all the magic happens.
  • Texts for Text Node – result_package_4 <- Not mandatory. Used for giving texts to text nodes.

5. The Code:

Right. So this is it, structurally. Moving on to the code which is the heart of this solution.

Below is the complete ABAP code that goes into the expert routine and that you can use directly as long as you have used the same InfoObject(0CUSTOMER) & attribute(ZCCST_GRP). Else, just appropriately replace them in the code with your InfoObject and attribute and the rest of the code can be used as-is.

I’ve added comments throughout to give an understanding of every logic. Although if you need any further help, let me know in the comments.

    IF SOURCE_PACKAGE IS NOT INITIAL.
      " Constants Declaration
      CONSTANTS: lc_hier      TYPE rshienm    VALUE 'HIER_CUST_GRP',
                 lc_act       TYPE rsobjvers  VALUE 'A',
                 lc_hier_node TYPE rsnodename VALUE '0HIER_NODE',
                 lc_customer  TYPE rsiobjnm   VALUE '0CUSTOMER',
                 lc_en        TYPE c LENGTH 2 VALUE 'EN'.
 
      " Data Declaration
      DATA: lv_prnt_id    TYPE rshienodid,
            lv_max_nodeid TYPE rshienodid.

      " Macro to increment a number by 1.
      DEFINE increment.
        &1 = &1 + 1.
      END-OF-DEFINITION.

      " Get technical ID (hieid) of customer group hierarchy
      SELECT SINGLE hieid
        FROM rshiedir
        INTO @DATA(lv_hieid_hier_cust_grp)
        WHERE hienm = @lc_hier.

      " Get the MAX node id. This is important. Simply put,
      " always take the max node id and start creating
      " your nodes by adding 1 to it to make sure you
      " don't end up using a node id that is already
      " being used.
      " Also, never use the "WHERE hieid =" clause here
      " as we want maximum node ID across all hierarchies
      " for 0CUSTOMER.
      SELECT SINGLE MAX( nodeid )
        FROM /bi0/hcustomer
        INTO lv_max_nodeid.

      " Get parents that already exist. This includes
      " everything - the root node & the leaves/leaf.
      " This needs to be selected only from our custom
      " hierarchy. So, use the "WHERE hieid =" clause.
      " In the case of multiple hierarchies, add all of 
      " them here, separated by "AND".
      SELECT hieid, nodeid, nodename
        FROM /bi0/hcustomer
        INTO TABLE @DATA(lt_existing_parents)
        WHERE hieid = @lv_hieid_hier_cust_grp
        AND   objvers = @lc_act.

      SORT lt_existing_parents BY hieid nodename.
      SORT SOURCE_PACKAGE BY customer.

      " lv_index will be used to increment the node ID.
      DATA(lv_index) = 00000000.

      LOOP AT SOURCE_PACKAGE ASSIGNING <source_fields>.
*--------------------------------------------------------------------*
*~~~~~~~~~~~~~~~~~~Process Hierarchy - HIER_CUST_GRP~~~~~~~~~~~~~~~~~*
*--------------------------------------------------------------------*
        IF <source_fields>-/bic/zccst_grp <> space.
          CLEAR RESULT_FIELDS_3.
          " Fill result_package_1 with the technical name
          " for the hierarchy.
          RESULT_PACKAGE_1 = VALUE #( BASE RESULT_PACKAGE_1 (
          objectid = lv_hieid_hier_cust_grp
          h_hienm = CONV char30( lc_hier )
          )  ).

          " Reading result_package_3 to check if we already have a
          " root node (customer group) added. If we have it already,
          " then it's a case of multiple customers per customer group.
          " So skip adding customer group again and keep adding the
          " customers for it.
          " ***(Don't use binary search here.)***
          " Sy-subrc = 0 means customer group already exists.
          READ TABLE RESULT_PACKAGE_3 INTO RESULT_FIELDS_3
          WITH KEY h_hiernode = <source_fields>-/bic/zccst_grp.
          IF sy-subrc <> 0.
            "See if we already have this customer group in hierarchy.
            READ TABLE lt_existing_parents ASSIGNING
            FIELD-SYMBOL(<ep_cust_grp>)
            WITH KEY hieid = lv_hieid_hier_cust_grp
                     nodename = <source_fields>-/bic/zccst_grp
            BINARY SEARCH.
            IF sy-subrc = 0.
              " We have the customer group already. So write its node_id
              " from lt_existing_parents table to result_package_3.
              " T_level will be 1 as it's root node.
              RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                        objectid = lv_hieid_hier_cust_grp
                        h_nodeid = <ep_cust_grp>-nodeid
                        h_hiernode = <source_fields>-/bic/zccst_grp
                        h_iobjnm = lc_hier_node
                        h_tlevel = 01 "Always 01
                        )  ).
              " Store parent_id. Will be used when adding customers.
              lv_prnt_id = <ep_cust_grp>-nodeid.
            ELSE.
              " Increment lv_index before (manually) adding any node.
              increment lv_index.

              " Customer grp neither already added to result_package_3,
              " nor exists in backend. So, it's a new customer group.
              RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                        objectid = lv_hieid_hier_cust_grp
                        h_nodeid = lv_max_nodeid + lv_index
                        h_hiernode = <source_fields>-/bic/zccst_grp
                        h_iobjnm = lc_hier_node
                        h_tlevel = 01 "Always 01
                        )  ).
              " Store parent_id. Will be used when adding customers.
              lv_prnt_id = lv_max_nodeid + lv_index.
            ENDIF.
          ELSE.
            " Store parent_id. Will be used when adding customers.
            lv_prnt_id = RESULT_FIELDS_3-h_nodeid.
          ENDIF.

          " Increment lv_index before (manually) adding any node.
          increment lv_index.

          " Check if customer already exists.
          " If it does, copy the node_id from lt_existing_parents to
          " result_package_3.
          " *** But do not copy the parent_id. ***
          " Parent_ID must be entered from lv_prnt_id var.
          " This will take care of the case where a customer is moved
          " from one customer group to another customer group.
          READ TABLE lt_existing_parents ASSIGNING
          FIELD-SYMBOL(<ep_cust_grp_1>)
          WITH KEY hieid = lv_hieid_hier_cust_grp
                   nodename = <source_fields>-customer
          BINARY SEARCH.
          IF sy-subrc = 0.
            RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
            objectid = lv_hieid_hier_cust_grp
            h_nodeid = <ep_cust_grp_1>-nodeid
            h_iobjnm = lc_customer
            customer = <source_fields>-customer
            h_parentid = lv_prnt_id "IMP!
            h_tlevel = 02 "Always 02
            )  ).
          ELSE.
            " New customer. Add to result_package_3.
            RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
            objectid = lv_hieid_hier_cust_grp
            h_nodeid = lv_max_nodeid + lv_index
            h_iobjnm = lc_customer
            customer = <source_fields>-customer
            h_parentid = lv_prnt_id
            h_tlevel = 02 "Always 02
            )  ).
          ENDIF.
          " Fill the Text in result_package_4 table.
          " Key is used as text here.
          " Always give value for langu. Texts only work
          " if a language is supplied.
          RESULT_PACKAGE_4 = VALUE #( BASE RESULT_PACKAGE_4 (
          objectid = lv_hieid_hier_cust_grp
          langu = lc_en
          h_hiernode = <source_fields>-/bic/zccst_grp
          txtlg = <source_fields>-/bic/zccst_grp
          txtmd = <source_fields>-/bic/zccst_grp
          txtsh = <source_fields>-/bic/zccst_grp
          )  ).
        ENDIF.
      ENDLOOP.
    ENDIF.

The code above simply takes all the customer groups in the source_package and creates a text node for each of them. Then it takes all the customers and adds them underneath their respective customer group nodes. result_package_3 is responsible for doing both.

lv_max_nodeid – this variable holds the maximum node id across all the hierarchies for our InfoObject. This will be used to ensure that we never overlap the node IDs of two different nodes.

lt_existing_parents – this internal table holds all the nodes that already exist for this hierarchy. So, for example, if node – ABC is already present, it will be held in this table. This is true for both – customer groups and customers. If you’re running this code for the first time, the internal table will be blank. Using this we can take care of the case when a customer moves from one customer group to another.

Note: Always give value for langu when populating result_package_4. Texts only work if a language is supplied.

6. Test Cases:

I have tested this solution extensively and found it working for all the cases mentioned below:

  1. Hierarchy Tampering – If someone manually deletes any text node or an inner node or anything really, just reload the DTP and all will be good.
  2. Data Update – If master data is updated in any way – a customer is deleted, added, or moved to another customer group, or a customer group is deleted or renamed or anything, reload the DTP and we will have an updated hierarchy as per the updated master data.
  3. Different Levels – I have used a simpler example to keep things straight – but you can change the T_Levels and create different text nodes and levels as per your requirement. Just add them all to result_package_3.
  4. Multiple Hierarchies – I originally wrote this blog showcasing generation of 2 different hierarchies but decided to go with one to keep things simple. I have used and tested 2 hierarchies but you can essentially generate any number of hierarchies using the code given. The code will need to be altered, yes. But once you understand how it works for a single hierarchy, it becomes rather simple to alter it for any further hierarchies.
  5. Performance – I have tested it thoroughly and performance won’t be a problem at all.
A hierarchy with around 25,000 nodes and the DTP loads within 
4 seconds.DTP

 

7. Multiple Hierarchies plus Time Dependent Hierarchies:

This section explains how to create multiple hierarchies and making them time dependent as well.

The concept remains the same. Just few settings need to be altered and few things need to be remembered.

For Multiple Hierarchies:

  • Always make sure you have a unique hier ID for every hierarchy created.
    • If you are creating a hierarchy for the first time, lv_hierid_* variable/s would be blank. In such a case always assign a unique value to the variables manually. I have assigned 1,2 and 3 to respective variables of the 3 hierarchies I’m generating.

For Time Dependent Hierarchies (structure level):

  • Hierarchy must first be set as Time Dependent. Go to Hierarchy tab and select radio button named – “Time-Dependent Hierarchy Structure”.
  • Dateto and Datefrom fields must be supplied in result_package_3 for every node you wish to be time-dependent.

Combined code showing both multiple hierarchies and time dependency:

https://mega.nz/file/tF0SVBSK#x9Yv8TMP4fMD4t1CNkOlpuE8UvMoQvTOEaiFvApS1Cs

8. Multi Level Hierarchies:

Points to be remembered:

  • Duplicate Nodes are only allowed for leaves (the last node).
    • Most of the errors you’ll get will be due to duplicate (non-leaf) nodes. Check if same name is being repeated at any level (non-leaf).

Code for multilevel hierarchies:

https://mega.nz/file/gV8SxDjC#J4XRnWkmJ10aT9yRc6YgQ5aT1WA17F2pMYy3-c4y674

9. Duplicate Leaf Nodes:

Points to be remembered:

Duplicate nodes are allowed in hierarchies only at leaf/lowest level. We can achieve this by reading result_package_3 before processing the leaf node and checking if it already exists for the combination of object_id, parent_id and value of the leaf (customer, in this case).

Also, if you are clubbing this with multiple hierarchies, remember to created a local variable for every hierarchy that stores the object id which will be used in READ statement at leaf level.

Variable used in this example:

lv_objectid_hier_zcustomer TYPE /bi0/oiobjectid.

READ statement:

READ TABLE RESULT_PACKAGE_3 INTO RESULT_FIELDS_3
WITH KEY objectid = lv_objectid_hier_zcustomer
         /bic/zcustomer = <source_fields>-/bic/zcustomer
         h_parentid = lv_prnt_id.

This is an example of a duplicate leaf node.

Code to allow duplicate leaf nodes:

https://mega.nz/file/wZ8SQZCa#fBnQYU_ziJeolSo76HoCgktjdy-YygpH-WLXC8BGghw

This brings us to the end of the blog. Let’s summarize:

  1. Create a transformation from ATTR to HIERARCHY and create an expert routine on it.
  2. Copy the code given above into the expert routine and alter it as per your requirements.
  3. ???
  4. Profit.

Do share your thoughts if you made it so far. Thanks.

 

Assigned tags

      57 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Corvin Schindler
      Corvin Schindler

      Hello Sagar,

      thanks for sharing the information. I recently encountered a 3.x DataSource with a CMOD implementation within the BW which cannot be migrated to BW/4HANA. The way you described, is a possible way to solve this.

      And you made my day with your summary. 🙂

      Best regards,

      Corvin

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Hi Corvin,

      I recently encountered a 3.x DataSource with a CMOD implementation within the BW which cannot be migrated to BW/4HANA

      Yes, many times we don’t even have a DataSource, especially for custom InfoObjects. This to me is a perfect solution for such cases. And it kind of makes hierarchy DataSources unnecessary, at least for simpler hierarchies (and if you’re comfortable with ABAP).

      The way you described, is a possible way to solve this.

      Please do update if this worked for you or not. Will be very useful for me and others.

      And you made my day with your summary.

      That was the intent. 🙂

      Regards,

      Sagar

      Author's profile photo Martin Maruskin
      Martin Maruskin

      Hello Sagar,

      great blog post! I was recently developing similar solution. One of the things I struggled with was how to generate an nodeid. I wasn't able to find any standard functionality (FM, class/method etc) that could generate it. So I ended up with same solution as you -> retrieve the highest nodeid and increase it by one. Any chance that you found something in this regard how to generate it?

      thanks

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Hello Martin,

      Frankly, I didn’t look for it. I expected SAP to have written a complete How-To guide on this topic but they didn’t. So, disappointedly, I decided to do it myself and go full custom on it as I only had half a day to come up with a working solution.

      It’s possible that there is an FM somewhere that does take care of nodeids for us but also equally possible that SAP like us just incremented the nodeids locally and didn’t release a separate FM for it.

      Regards,

      Sagar

      Author's profile photo Martin Maruskin
      Martin Maruskin

      Hi Sagar,

      one more thing. I was curious whether you managed to add also short / medium and long description of hierarchy header. I mean the texts that are appearing in hierarchy maintenance screen in SAP GUI.

      I thought that it should be handled by using source_package_1 table but that table has only following fields:

      OBJECTID
      H_HIENM
      H_NORESTNO
      H_STARTLEV
      H_NODEPOS
      H_LEAFNOD
      H_ALEAFNOC
      H_TIMESTMP
      LOGSYS
      RECORD

      So it doesn't appear to be done that way. Any experience with how could we maintain those texts from the data load? Thanks

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Hello Marcus,

      The portion of the code below takes care of texts:

                " Fill the Text in result_package_4 table.
                " Key is used as text here.
                RESULT_PACKAGE_4 = VALUE #( BASE RESULT_PACKAGE_4 (
                objectid = lv_hieid_hier_cust_grp
                langu = lc_en
                h_hiernode = <source_fields>-/bic/zccst_grp
                txtlg = <source_fields>-/bic/zccst_grp
                txtmd = <source_fields>-/bic/zccst_grp
                txtsh = <source_fields>-/bic/zccst_grp
                )  ).

      Just fill result_package_4 as shown above. Remember to always give value for ‘langu’.

      Texts seem to work only if we give language. I’ll mention this in the blog itself as well. Let me know if it works.

      Regards.

      Author's profile photo Martin Maruskin
      Martin Maruskin

      Hi Sagar,

      unfortunately in my case it doesn't work. The result_package_4 itab seems to carry hierarchy header but in my case that uses expert routine it doesn't.

      Anyhow thanks!

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      This should work though, Martin. It puzzles me that it doesn't work for you. Would it be okay for you to share a screenshot of your result_package_4? It will help others who read this blog as well.

      Do you not see the langu, textsh etc. fields in there?

       

      Author's profile photo Martin Maruskin
      Martin Maruskin

      Finally it is working, the table that is supposed to be used to address those texts is second one, e.g. RESULT_PACKAGE_2

      Thanks for your help.

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Well, that's good. But it's strange you have texts in result_package_2. May I ask what version of BW you are working on? Because I tested on 3 different systems and all had texts in result_package_4.

      Author's profile photo Martin Maruskin
      Martin Maruskin

      Hi Sagar,

      tab2 is for hierarchy header descriptions. into tab4 regular hierarchy records texts are put. Hope this clarify it.

      cheers

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      ok, thanks for letting me know Martin. I thought you were after texts and not descriptions. Glad it worked.

      Author's profile photo Xiaofang Liu
      Xiaofang Liu

      It's quite good. I used this method to bypass the 3.x datasource method.

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Thanks, Xiaofang.

      Author's profile photo Iksit Gadhia
      Iksit Gadhia

      Hi,

       

      Im not a great abapper so would appreciate you help. I need something like this but for 5 levels of attributes that appear in the infoobject.

       

      So I guess...

       

      Create the top text nodes

      Create more text nodes with respect to parents

      again as above

      again as above

      again as above

      then the infoobject characteristic values, as always, with respect to parents!

       

       

      how does the abap change to accommodate for this... you mention T_LEVELS but to be honest, this abap is over my pay grade. Can you give me any hints?

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Iksit, the basis of increasing hierarchy levels is to increment the T_LEVELS as stated in the blog. But it isn't only restricted to that. There are some obvious steps attached to it.

      To get the result similar to shown in the screenshot below, try to understand the sample code that follows. It's fairly simple.

      In the code below, Please try to understand the usage of first_chilld, second_child, and final_child. You just have to replace them with your respective InfoObjects.

                " TLevel = 2          
                READ TABLE RESULT_PACKAGE_3 INTO RESULT_FIELDS_3
                WITH KEY h_hiernode = <source_fields>-first_child.
                IF sy-subrc <> 0.            
                  READ TABLE lt_existing_parents ASSIGNING
                  FIELD-SYMBOL(<ep1>)
                  WITH KEY hieid = lv_hieid_hier
                           nodename = <source_fields>-first_child
                  BINARY SEARCH.
                  IF sy-subrc = 0.
                    RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                    objectid = lv_hieid_hier
                    h_nodeid = <ep1>-nodeid
                    h_iobjnm = lc_hier_node
                    h_hiernode = <source_fields>-first_child
                    h_parentid = lv_prnt_id "IMP!
                    h_tlevel = 02 "Always 02
                    )  ).
                  ELSE.         
                    RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                    objectid = lv_hieid_hier
                    h_nodeid = lv_max_nodeid + lv_index
                    h_iobjnm = lc_hier_node
                    h_hiernode = <source_fields>-first_child
                    h_parentid = lv_prnt_id
                    h_tlevel = 02 "Always 02
                    )  ).
                  ENDIF.
                  lv_prnt_id = lv_max_nodeid + lv_index.
                  increment lv_index.
                ELSE.
                  lv_prnt_id = RESULT_FIELDS_3-h_nodeid.
                ENDIF.
      
                " TLevel = 3
                READ TABLE RESULT_PACKAGE_3 INTO RESULT_FIELDS_3
                WITH KEY h_hiernode = <source_fields>-second_child.
                IF sy-subrc <> 0.
                  READ TABLE lt_existing_parents ASSIGNING
                  FIELD-SYMBOL(<ep2>)
                  WITH KEY hieid = lv_hieid_hier
                           nodename = <source_fields>-second_child
                  BINARY SEARCH.
                  IF sy-subrc = 0.
                    RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                    objectid = lv_hieid_hier
                    h_nodeid = <ep2>-nodeid
                    h_iobjnm = lc_hier_node
                    h_hiernode = <source_fields>-second_child
                    h_parentid = lv_prnt_id "IMP!
                    h_tlevel = 03 "Always 03
                    )  ).
                  ELSE.
                    " New gl_account. Add to result_package_3.
                    RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                    objectid = lv_hieid_hier
                    h_nodeid = lv_max_nodeid + lv_index
                    h_iobjnm = lc_hier_node
                    h_hiernode = <source_fields>-second_child
                    h_parentid = lv_prnt_id
                    h_tlevel = 03 "Always 03
                    )  ).
                  ENDIF.
                  lv_prnt_id = lv_max_nodeid + lv_index.
                  increment lv_index.
                ELSE.
                  lv_prnt_id = RESULT_FIELDS_3-h_nodeid.
                ENDIF.
      
                " TLevel = 4
                READ TABLE lt_existing_parents ASSIGNING
                FIELD-SYMBOL(<ep3>)
                WITH KEY hieid = lv_hieid_hier
                         nodename = <source_fields>-final_child
                BINARY SEARCH.
                IF sy-subrc = 0.
                  RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                  objectid = lv_hieid_hier
                  h_nodeid = <ep3>-nodeid
                  h_iobjnm = 'final_child'
                  final_child = <source_fields>-final_child
                  h_parentid = lv_prnt_id "IMP!
                  h_tlevel = 04 "Always 04
                  )  ).
                ELSE.
                  RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
                  objectid = lv_hieid_hier
                  h_nodeid = lv_max_nodeid + lv_index
                  h_iobjnm = 'final_child'
                  final_child = <source_fields>-final_child
                  h_parentid = lv_prnt_id
                  h_tlevel = 04 "Always 04
                  )  ).
                ENDIF.

      I don't have any time to update the blog right now, so have given an example code here. Later, I'll update the blog with more complex scenarios.

      Author's profile photo Pavel Kozmenko
      Pavel Kozmenko

      Hi Sagar,

      Thanks for sharing. We're facing unexpectable issue with this method. While creating HIER transformation from ATTR of the same infoobject the system doesn't popup the screen of chose whether we want to create an ABAP expert routine or AMDP script and creates AMDP by default. Have you faced this problem anyhow? All transformations to ADSO have the option to chose. We're on 7.5sp16 on HANA.

      Thanks,

      Pavel

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      That's a strange problem, Pavel, I must say. I've always had the popup come up with the option to choose ABAP or to create an AMDP. Not sure what went awry. Try asking this as a question on answers.sap.com.

       

      Author's profile photo Sven Boetius
      Sven Boetius

      Hi Pavel,

       

      if it is still relevant: We had the same problem on another issue.

      If you used AMDP scripts before in this trasnsformation and deleted them to switch to ABAP, it is possible, that the routine is not deleted correctly, and lurks invisibly in the transformation. With CL_RSTRAN_STAT->DELTE_RULE_FROM_DB these invisible routines can be deleted.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      First of all appreciate for the great blog.I too facing the same issue. I have a cost center and SITE is an attribute for the Cost Center.I followed the same process.

      I am not a great ABAPer But reading the table RSHIEDIR i didnt find an entry for SITE.Could you please help me on this.

      Regards,

      Pamarthy.

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Pamarthy,

      Thanks for your appreciation. You don’t need an entry in the table RSHIEDIR. Firstly, copy the whole code from the blog and paste it into your expert routine. And then, do the following:,

      Change “lc_hier” constant to whatever technical name of hierarchy you want. Example below:

      lc_hier = 'HIER_COST_CENTER'

      Now, change “lc_customer” to “lc_cost_center” and change its value as well. Example below:

      lc_cost_center  TYPE rsiobjnm   VALUE '0COSTCENTER'

      Now, just do some find and replace (ctrl + H in windows).

      • Throughout the code, replace lc_customer with lc_cost_center.
      • Throughout the code, replace /bic/zccst_grp with SITE. “SITE” for standard IO and “/BIC/ZSITE” for custom. (Assuming ZSITE is the technical name of custom IO.)

      This should be it. Try this and let me know if you get any errors.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

       

      Great man. Wonder with your immediate reply and thanks a lot.Let me do it and will let you know if I need some help.

      Regards,

      Neel.

       

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      I am getting the error with source fields does not have component called /BIC.Could you please look into the code and suggest me if I am in right track. I am not an ABAPer.I am very thankful to you

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Kindly edit your comment and remove all the code. Add only these things:

      • Screenshot of error
      • Technical name of SITE Infoobject
      • Technical name of CostCenter infoobject.

      This error is related to incorrect naming.

      Remember the naming convention: "/bic/"zinfoobject for custom IO and "infoobject" for standard.

      Example for ZCOSTCENTER, use /BIC/ZCOSTCENTER. For 0COSTCENTER, use COSTCENTER (without the 0).

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Thanks for the reply. Now I found there were no syntax errors. But one problem I am facing is I loaded the data and didn't find any Hierarchy for SITE in Cost center. Appreciate your comments.

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Okay. That's progress. I can't help further without looking at the final code though. I'd request you to please do a code compare. Use this website - https://www.diffchecker.com/. Make sure the code I've given matches the code you've written, barring the necessary changes.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Good Morning. The code is working now and I ran the dtp.I have a small doubt. My code is

       CONSTANTSlc_hier      TYPE rshienm    VALUE 'HIER_COST_CENTER',
                       lc_act       TYPE rsobjvers  VALUE 'A',
                       lc_hier_node TYPE rsnodename VALUE '0HIER_NODE',
                       lc_cost_center TYPE rsiobjnm   VALUE 'COCCOSCTR',
                       lc_en        TYPE LENGTH VALUE 'EN'.
      what is the first select will do.
      SELECT SINGLE hieid
              FROM rshiedir
              INTO @DATA(lv_hieid_hier_site_grp)
              WHERE hienm @lc_hier.
      Do I need to declare my LC_Hier as the existing cost center Hierarchy name? When I debug I am not getting any value into LV_HIEID_HIER_SITE_GRP.

      Regards,

      Neel.

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Output of the first select is used in third select to check if the hierarchy already exists. If it does, we’ll update the hierarchy later on with the changes.

      This handles the delta changes. For ex, if a cost center is moved from one site to another, lv_hieid_hier_site_grp is going to be used for handling it.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Thanks for your kind support and very nice of your explanation. I tried loading the data but getting errors. attached is the screenshot of my debug reference and the error that I am getting while updating the Hierarchy. Once again thanks a lot for all you done to me.

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Kindly upload your code to a cloud storage (Google Drive/Mega etc.) and provide its link. I can have a look.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Attached is the link for reference.

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      I see you are using time dependent master data. That’s where the problem is. My bad, should’ve mentioned the code I used is for time-independent only.

      For your case, do the following:

      • In Infoobject’s Hierarchy tab, select the Time-Dependent radio button as shown below.

      radio

      • Wherever result_package_3 is used, append the following lines:
      datefrom = <source_fields>-datefrom
      dateto = <source_fields>-dateto

      Example:

      RESULT_PACKAGE_3 = VALUE #( BASE RESULT_PACKAGE_3 (
      objectid = lv_hieid_hier
      h_nodeid = <ep2>-nodeid
      h_iobjnm = lc_hier_node
      h_hiernode = <source_fields>-second_child
      " Capture Time Dependency by using dateto and datefrom
      datefrom = <source_fields>-datefrom
      dateto = <source_fields>-dateto
      h_parentid = lv_prnt_id "IMP!
      h_tlevel = 03 "Always 03

      Try and let me know if it works.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Sorry for delay in my reply.Today I am off. Thanks for the advice and I think I need to do some analysis on the property change and also look at the permissions from the concern teams. I will let you know once I can change the hierarchy property. just to inform you that I will remove the link.

      Once again thanks for your kind help.

       

       

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Sorry  for delay. Today I am off. I wrote a mail to concern team to change the property.I will update you once I got the response.

      Just to inform you that I will remove the link. Thanks and really thankful to you for your extended help.

      Regards,

      Neel.

      Author's profile photo Prasanna Ganorkar
      Prasanna Ganorkar

      Hello Sagar,

       

      Thank you for the post, it has made creating hierarchy much simpler.
      However I wanted to know, if we want to load more than one hierarchy, what changes should we make in the code.
      Both the hierarchies will be created using the same code.

       

      Thanks

      Prasanna.

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Prasanna,

      More than one hierarchies will be created using the same code. Yes. Unfortunately, you'll need to completely understand how the code works for it. Once you do, it's just a matter of doing the same stuff again for the second hierarchy and again for the third and so on.

      In short changes would be:

      • Select queries - where ever the hierarchy's tech name is used - should be changed.
      • Similarly, all the result packages - result_package_1, _3, & _4 would need to be appended for the additional hierarchy.
      • Max_node_id must be handled for every hierarchy that you add to the solution.

      In other words, it's like doing the same thing over and over again for every additional hierarchy. You can create a class and have different methods for different hierarchies in it. All of them doing the same thing by having different loops over source_package for every hierarchy. This would keep the code much cleaner. But will degrade the performance ever so slightly. The performance hit should be negligible though and I'd prefer it to have a cleaner code. Doing it inside the same loop is also possible but can get a bit complex to understand.

      But again, understanding the code and the hierarchy concepts is crucial to replicate it.

      Author's profile photo Sekhar Kari
      Sekhar Kari

      Hi Sagar,

       I am getting the below error while defining the level3  Hierarchy and can you please let me know solution to over come the issue. Thanks in advance.

       

      Thanks,

      Sekhar.Kari

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Node ID is being repeated for some records. This should never be the case. Make sure Node ID is always unique for every single row/record.

      Author's profile photo Sekhar Kari
      Sekhar Kari

      Hi Sagar,

      Thanks for your answer and can you please elaborate on basis we can delete the adjacent duplicates to to get the unique records.

      Thanks,

      Sekhar.Kari

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      I can’t comment on needing Delete Adjacent Duplicates without knowing your requirement. Node ID must be handled in the code only and not by deleting duplicate values.

      Rule of thumb for node ID is:

      Every node must have a unique node ID. Either by incrementing by one for every node or by reading the existing node ID value.

      Do you have duplicate nodes in your hierarchy? That could cause some errors.

      Author's profile photo Sekhar Kari
      Sekhar Kari

      Hi Sagar,

      my Source is an Adso with flat structure of data and I want  to convert into hierarchy data of an info object. In this scenario what is the approach of hierarchy transformation.

      Thanks,

      Sekhar.Kari

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      Anything that can be connected to a Hierarchy transformation can be used as a source. So, aDSO should be fine as well. Approach will remain the same. Source -> Hierarchy Transformation and an expert routine on that transformation.

      Author's profile photo Sekhar Kari
      Sekhar Kari

      Hi Sagar,

      Thanks for your clarification and it really helps me a lot.

      Thanks,

      Sekhar.Kari

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      All,

      I'll be soon adding the following advanced cases:

      • Multiple hierarchies. Example with 3 hierarchies in single code.
      • Time Dependent hierarchies.
      • Hierarchies with multiple levels.

      The first two cases are done. I'll be working on third tomorrow and will update the blog by - or on - the weekend.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Its really great to hear that. I really need and waiting for the second scenario that I am currently working on.I felt ashamed to ping you more and more times is the reason why I became silent.

      Regards,

      Neel.

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      🙂

      I'll be disappointed if this doesn't work for someone. So, I'm actually fine with questions. No need to feel bad.

      But please understand that a certain level of ABAP understanding is required for this to work. You should be able to tweak and debug the code and understand any errors that come up.

      Please check the time dependent example once I upload it and see if you can easily replicate that. If you can't, please raise a question on answers.sap.com and we can discuss further there.

      All,

      If you need detailed help on code, please raise a question on answers.sap.com. The blog is more  about describing the solution/architecture that can be used to achieve this requirement than just the ABAP part.

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,,

      Hope you are doing good. I have a doubt. Can I able to create the hierarchy by using other Info Object Attributes. for Example I have Cost Center Global and cost center local.I want to create a Hierarchy on Cost center global by using the attributes of cost center local.If so what are all the required modifications that I need to do for the existing code.

      Regards,

      Neel.

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      It's not any different, Neel. You can create a transformation from attributes of local costcenter to hierarchy of global costcenter and then create an expert routine on top of it.

      Code changes will be the same like you would do on a self-transformation. Give it a try.

      Author's profile photo neel pamarthy
      neel pamarthy

      Yes Sagar,

      Really thankful to your cooperation.Yes i got succeeded to generate the same.

      Nice of your quick response.

      Regards,

      Neel.

       

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Hope you are doing good. I need a small help. I have to concatenate Client with node id.Could you please advice me how can I achieve it.

      Regatds,

      Neel.

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      That is a pure ABAP question, Neel. Kindly post it on answers.sap.com

      Author's profile photo neel pamarthy
      neel pamarthy

      Hi Sagar,

      Hope you are doing good.I have a small doubt. I concatenated node id with client. But after that my codeis creating duplicate nodes. For example if my site have two cost centers it is creating same node as an individual nodes separately for two different cost centers. Appreciate your suggestion.

      https://drive.google.com/file/d/1cLvnfMDYQCz6ucIrXnJGkucMLyr2X3TS/view?usp=sharing

      Regards,

      Neel.

      Author's profile photo Thakkar Ketan
      Thakkar Ketan

      Hi Sagar,

      Hierarchy node text is not getting populated.

      I have tried the same steps as mentioned by you.

      Child node text is getting populated.

      Can you suggest here.

       

      Also if the reload same DTP again is giving error for Node ID already exist.

       

       

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      The only reason this happens is because of incorrect code. Try getting it corrected with help of an ABAPer.

       

      Author's profile photo komal prabhu
      komal prabhu

      Hello Sagar,

      Good Blog.

      According to this i am writing multi. level hirarchy code (which is not time dependednd but its failing)

      Error is  : " Node ID 00000008 occurs more than once in Hirarchy table.

      when i checked table (itab3) in backend , then i dont found any duplicate node id.

       

      I would glad if you post the code for 2 hirarchy(not time depended)

      Thanks.

      Author's profile photo Sagar Sheokand
      Sagar Sheokand
      Blog Post Author

      This should be simple to debug. Place a breakpoint at the very end of your code, where you have finished populating all the result_packages - most importantly, result_package_3.

      Then see the content of result_package_3 - you'll see node ID 00000008 is being repeated somewhere. If not, check the H table and you'll see node ID 00000008 is being used already.

      It has to be either of these cases. Please ensure a node ID is never repeated and you should be good.

       

      Author's profile photo komal prabhu
      komal prabhu

      thanks for reply.

      i will check and back to you.