Skip to Content
Technical Articles
Author's profile photo Ujjwal Singh

Lets discuss some good practices of coding

This blog will help folks who just on-boarded for ABAP in understanding the codes in line with it.

Note: 1st block of code indicates incorrect way of coding. Codes that follow the golden rules are written just after that.

1. Having small result sets

1.1 WHERE condition

Requirement: Fetch customers whose customer type is ‘B’.

DATA : lv_id TYPE scustom-id,
       lv_name TYPE scustom-name,
       lv_discount TYPE scustom-discount,
       lv_custtype TYPE scustom-custtype.
  • Bad Practice
SELECT id name discount custtype FROM scustom
INTO (lv_id, lv_name, lv_discount, lv_custtype).
IF lv_custtype = 'B'.
WRITE : / lv_id, lv_name, lv_discount, lv_custtype.
ENDIF.
ENDSELECT.
  • Good Practice
TYPES: BEGIN OF ty_scustom,
id       TYPE S_CUSTOMER,
name     TYPE S_CUSTNAME,
discount TYPE S_DISCOUNT,
custtype TYPE S_CUSTTYPE,
       END OF ty_scustom.

DATA: it_scuctom TYPE TABLE OF ty_scustom,
      wa_scustom TYPE ty_scustom.
SELECT id name discount custtype FROM scustom
INTO TABLE it_scustom   
WHERE custtype = 'B'.
LOOP AT it_scustom INTO wa_scustom.
WRITE : / wa_scustom-id, wa_scustom-name, 
          wa_scustom-discount, wa_scustom-custtype.
ENDLOOP.

Reason: Fetching filtered data is better than fetching the entire data set and then filtering it.

1.2 HAVING clause

Requirement: Fetch details of flights having the minimum seat occupancy. The minimum seat occupancy should be greater than zero.

DATA: lv_sflight TYPE sflight,
      lv_min     TYPE sflight-seatsocc.
  • Bad Practice
SELECT carrid connid MIN( seatsocc ) FROM sflight
INTO (lv_sflight-carrid, lv_sflight-connid, lv_min)
GROUP BY carrid connid.
IF lv_min > 0.
WRITE:/ lv_sflight-carrid, lv_sflight-connid, lv_min.
ENDIF.
ENDSELECT.
  • Good Practice
TYPES: BEGIN OF ty_sflight,
carrid   TYPE S_CARR_ID,
connid   TYPE S_CONN_ID,
seatsocc TYPE S_SEATSOCC,
       END OF ty_sflight.

DATA: it_sflight TYPE TABLE OF ty_sflight,
      wa_sflight TYPE ty_sflight.
SELECT carrid connid MIN( seatsocc ) FROM sflight
INTO TABLE it_sflight
GROUP BY carrid connid 
HAVING MIN( seatsocc ) > 0.
LOOP AT it_sflight INTO wa_sflight.
WRITE:/ wa_sflight-carrid, wa_sflight-connid, wa_sflight-min_socc.
END LOOP.

Reason: Do the calculation in the select query itself

1.3 Transferring required rows

Requirement: Fetch details

DATA: lt_scustom TYPE TABLE OF scustom,
      lw_scustom TYPE scustom.
  • Bad Practice
SELECT id name discount custtype FROM scustom
INTO CORRESPONDING FIELDS OF TABLE lt_scustom
WHERE country = 'DE'.
DELETE lt_scustom WHERE custtype = 'P'.
LOOP AT lt_scustom INTO lw_scustom.
WRITE: / lw_scustom -id, lw_scustom -name, 
         lw_scustom-discount, lw_scustom -custtype.
ENDLOOP.
  • Good Practice
SELECT id name discount custtype FROM scustom
INTO CORRESPONDING FIELDS OF TABLE lt_scustom
WHERE country = 'DE' AND custtype <> 'P'.
LOOP AT lt_scustom INTO lw_scustom.
WRITE: / lw_scustom-id, lw_scustom-name, 
         lw_scustom-discount, lw_scustom-custtype.
ENDLOOP.

Reason: Fetching required rows is better than fetching the entire data set and then delete the unwanted rows

2. Having small transferred data sets

2.1 DISTINCT clause

Requirement: Fetch distinct details of customers who avail discounts

DATA : lt_scustom TYPE TABLE OF scustom,
       lw_scustom TYPE scustom.
  • Bad Practice
SELECT custtype discount FROM scustom
INTO CORRESPONDING FIELDS OF TABLE lt_scustom
WHERE discount > 0
ORDER BY custtype discount DESCENDING.
DELETE ADJACENT DUPLICATES FROM lt_scustom.
LOOP AT lt_scustom INTO lw_scustom.
WRITE : / lw_scustom-id, lw_scustom-discount.
ENDLOOP.
  • Good Practice
SELECT DISTINCT custtype discount FROM scustom 
INTO CORRESPONDING FIELDS OF TABLE lt_scustom
WHERE discount > 0
ORDER BY custtype discount DESCENDING.
LOOP AT lt_scustom INTO lw_scustom.
WRITE : / lw_scustom-id, lw_scustom-discount.
ENDLOOP.

2.2 Using aggregate functions

Requirement: Display the total number of seats reserved in an airline in any given year

DATA : lv_sum      TYPE sflight-seatsocc,
       lv_seatsocc TYPE sflight-seatsocc.
  • Bad Practice
SELECT seatsocc FROM sflight 
INTO lv_seatsocc
WHERE carrid = 'LH'AND fldate LIKE '2013 %'.
lv_sum = lv_sum + lv_seatsocc.
ENDSELECT.
WRITE : / lv_sum.
  • Good Practice
SELECT SUM( seatsocc )FROM sflight 
INTO lv_sum
WHERE carrid = 'LH'AND fldate LIKE '2013 %'.
WRITE : / lv_sum.

2.3 Changing only required columns

Requirement: Change the connection number of a specific flight

DATA : lw_book TYPE sbook.
  • Bad Practice
SELECT * FROM sbook
INTO lw_book
WHERE carrid = 'LH'AND connid = '0400'AND fldate >= '20160101'.
lw_book-connid = '0500'.
UPDATE sbook FROM lw_book.ENDSELECT.
  • Good Practice
UPDATE sbookSET connid ='0500'
WHERE carrid = 'LH' AND connid = '0400' AND fldate >= '20160101'.

3. Reducing number of queries

3.1 Using set operations instead of individual operations

Requirement: Insert a record into the table SBOOK

  • Bad Practice
LOOP AT it_sbook INTO lw_sbook.
INSERT INTO sbook VALUES lw_sbook.
ENDLOOP.
  • Good Practice
INSERT sbook FROM TABLE lt_sbook.

3.2 Avoiding multiple accesses

Requirement: Delete details of flights with carrier ID AA and connection ID 17

  • Bad Practice
SELECT SINGLE * FROM sflight
INTO lv_sflight WHERE carrid = 'AA' AND connid = '0017'.
IF sy-subrc EQ 0.
DELETE FROM sflight WHERE carrid = 'AA' AND connid = '0017'.
IF sy-subrc EQ 0.
COMMIT WORK.
ENDIF.
ENDIF.
  • Good Practice
DELETE FROM sflight 
WHERE carrid = 'AA' AND connid = '0017'.
IF sy-subrc EQ 0.
COMMIT WORK.
ENDIF.

Reason: Delete data in the repository directly instead of fetching the dataset and then deleting it

3.3 Avoiding SELECT inside LOOPs

Requirement: Fetch details

  • Bad Practice
LOOP AT lt_sflight INTO lw_sflight.
SELECT SINGLE bookid customid FROM sbook
INTO lw_sbook
WHERE carrid = lv_sflight-carrid AND connid = lv_sflight-connid
AND fldate = lv_sflight-fldate.
WRITE : / lv_sflight-carrid, lv_sflight-connid, lv_sflight-fldate,
          lv_sbook-bookid, lv_sbook-customid.
ENDLOOP.
  • Good Practice
IF lt_sflight IS NOT INITIAL.
SELECT SINGLE bookid customid FROM sbook
INTO CORRESPONDING FIELDS OF TABLE lt_sbook
FOR ALL ENTRIES IN lt_sflight
WHERE carrid = lv_sflight-carrid AND connid = lv_sflight-connid
  AND fldate = lv_sflight-fldate.
ENDIF.

Assigned Tags

      6 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo LAN XIAO
      LAN XIAO

      i find nothing about hana.......

      Author's profile photo Matthew Billingham
      Matthew Billingham

      All of these could apply to any db system connected to SAP. This has nothing to do with HANA specifically.

      You could make it clearer that the first code presented is the bad one and the second is what you consider good, by having a little title before each, each time. 

      It would also be better if you use the code button to format code in your blog. That’s the {;} button in the editor.

      Your example of existence check is not best practice. That would be:

      SELECT SINGLE abap_true INTO @DATA(record_exists) FROM <table> WHERE <where_condition>.

      In this instance, it doesn’t even matter if the where condition doesn’t cover index fields. (You’ll also see from this example how nice the code editor makes code look).

      SELECT... ENDSELECT is generally considered an anti-pattern.

      Author's profile photo Ujjwal Singh
      Ujjwal Singh
      Blog Post Author

      Thank you Matthew for going through the blog and sharing the feedback.

      Changes has been made accordingly.

      Author's profile photo Sandra Rossi
      Sandra Rossi

      Please, could you use the formatting button to format your code? It looks horrible (cf the code that Matthew posted is well presented)

      Author's profile photo Ujjwal Singh
      Ujjwal Singh
      Blog Post Author

      Thanks for the suggestion @Sandra . Code really looks good now, after the formatting.

      Author's profile photo Jelena Perfiljeva
      Jelena Perfiljeva

      When sharing "good" and "bad" examples both examples should do the same thing. In the very first item (1.1) the examples do different things. (The "bad" one does not fill in an internal table, the "good" one does.)

      2.1 - different examples again, the first one will not pass a syntax check, I suspect.

      Prefixes like LV_ are no longer considered a good practice. Look up DSAG ABAP guidelines.

      ABAP guidelines and examples are included in the documentation, by the way. Transaction ABAPDOCU. Or, if you are in an older system, Google "ABAP keyword documentation" for a recent version online.