"
Supported by

The *_SINGLE_READ functions

When you need to derive a single record from a database table, you normally use SELECT SINGLE, which is like this in its most basic form, as everyone knows:


SELECT SINGLE *
  FROM KNA1
  WHERE KUNNR = '1234567890'.

Of course, if you are interested in just a few fields, ideally you select them explicitly to avoid copying unnecessary data from one side to the other:


DATA: lv_name1 TYPE name1.

SELECT SINGLE name1 INTO lv_name1
  FROM KNA1
  WHERE KUNNR = '1234567890'.

But this is all obvious and I am rambling as none of this is what brings me to this subject today. Today I want to talk about the valuable standard functions that replace SELECT SINGLE. Many of SAP’s main tables have functions that replace it as their job is precisely to derive records from those tables. For example, the function to derive a record of KNA1 is called KNA1_SINGLE_READ:


DATA: wa_kna1 TYPE kna1.

CALL FUNCTION 'KNA1_SINGLE_READ'
  EXPORTING
    kna1_kunnr       = '1234567890'
  IMPORTING
    WKNA1            = wa_kna1
  EXCEPTIONS
    NOT_FOUND        = 1
    OTHERS           = 2.

The big advantage of using these functions instead of SELECT SINGLE is that they make a cache of the values requested already. Imagine a scenario where we have 1000 sales orders for which we want to derive the KNA1 record. Most probably, those 1000 orders belong to a small number of clients. So if we do 1000 SELECT SINGLES on KNA1 we will request the same thing several times unnecessarily from the database:


LOOP AT lt_vbak ASSIGNING <vbak>.
  SELECT SINGLE * FROM KNA1
    INTO wa_kna1
    WHERE kunnr = <vbak>-kunnr.
  " (...)
ENDLOOP.

Performance-wise this is very bad. The dull and laborious alternative is first to derive a list of the different clients and then do a LOOP on those clients:


TYPES: BEGIN OF ty_kna1,        
        kunnr TYPE kunnr,
        name1 TYPE name1,
      END OF ty_kna1 .

DATA: lt_vbak TYPE STANDARD TABLE OF vbak,
      lt_kna1 TYPE STANDARD TABLE OF ty_kna1,
      wa_kna1 LIKE LINE OF lt_kna1.

FIELD-SYMBOLS: <vbak> LIKE LINE OF lt_vbak,
               <kna1> LIKE LINE OF lt_kna1.

* 1. Obter todas as ordens de venda
SELECT * FROM vbak 
  INTO TABLE lt_vbak
  WHERE vbeln IN so_vbeln  " parâmetro do report

* 2. Obter os diferentes KUNNRs
LOOP AT lt_vbak ASSIGNING <vbak>.
  wa_kna1-kunnr = <vbak>-kunnr.
  COLLECT wa_kna1 INTO lt_kna1.
ENDLOOP.

* 3. Obter os NAME1 da KNA1
LOOP AT lt_kna1 ASSIGNING <kna1>.
  SELECT SINGLE name1 INTO <kna1>-name1
    FROM kna1
    WHERE kunnr = <kna1>-kunnr.
ENDLOOP.

* 4 Loop das ordens de venda
LOOP AT lt_vbak ASSIGNING <vbak>.
  READ TABLE lt_kna1 ASSIGNING <kna1> WITH KEY kunnr = <vbak>-kunnr.
  " (...)
ENDLOOP.

But now see how much easier it is to use KNA1_SINGLE_READ:


DATA: lt_vbak TYPE STANDARD TABLE OF vbak,      
          wa_kna1 TYPE kna1.

FIELD-SYMBOLS: <vbak> LIKE LINE OF lt_vbak.

* 1. Obter todas as ordens de venda
SELECT * FROM vbak 
  INTO TABLE lt_vbak
  WHERE vbeln IN so_vbeln  " parâmetro do report

* 2. Loop das ordens de venda
LOOP AT lt_vbak ASSIGNING <vbak>.
  CALL FUNCTION 'KNA1_SINGLE_READ'
    EXPORTING
      kna1_kunnr = <vbak>-kunnr
    IMPORTING
      wkna1      = wa_kna1
    EXCEPTIONS
      not_found  = 1
      OTHERS     = 2.
  IF sy-subrc <> 0.
    " (...)
  ENDIF.
ENDLOOP.

A little simpler, no? And this solution is as fast as or faster than the previous one because KNA1_SINGLE_READ makes a cache automatically of the records already requested. And it is not just me saying so. SAP advises use of the *_SINGLE_READ functions whenever possible.

Note that if you are sure you will never request the same record twice, it is not worth using them and you are better off doing SELECT SINGLE as you will not benefit from the cache.

For many of the tables, aside from *_SINGLE_READ there are also similar functions that allow several records to be read in one go. For example, MARA_ARRAY_READ. Just go and explore.

As I already said, not all the tables have functions like this, but I am not going to tell you how to work with each SAP table because, as there are thousands and thousands, the post would get rather long. So it will have to be up to you to find them. But finding these functions is very easy and is almost always done in the same way: in SE37 search for the table name followed by *. If you’re still not following, here is an example:
for table T001W search for T001W*, and you will be sure to find something.

Greetings from Abapinho.

6 comentários a “The *_SINGLE_READ functions”

  1. André Diz:

    A SAP pode aconselhar a utilizar as funções, mas é extremamente desaconselháveis select dentro de loop. Talvez o que ela quer dizer é que quando é necessário fazer um select single em alguma tabela, por exemplo em um module pool, é melhor utilizar a função para não ficar fazendo chamada no banco de dados.

    Agora para seleção acima é bem melhor fazer a seleção na VBAK e depois fazer a seleção na KNA1 eliminando os KUNNR duplicados e utilizando FOR ALL ENTRIES e depois você dá um LOOP na tabela interna para recuperar seus dados…

  2. Nuno Godinho Diz:

    Pensando bem, André, acho que tu tens razão. Realmente quanto menos chamadas forem feitas à base de dados melhor e é preferível fazer tudo de uma vez. Obrigado.

  3. Pedro Lima Diz:

    É verdade que usar o FOR ALL ENTRIES é mais eficiente mas usar as funções *_SINGLE_READ (ou programar segundo a mesma estratégia de cache) tem uma grande vantagem. Permite tornar o código modular com blocos que fazem uma determinada função e que podem ser usados individualmente ou dentro de loops. É verdade que vai ter mais acessos à base de dados, mas usando cache o impacto é minimizado e, na minha opinião, vale a pena sacrificar um bocadinho de performance para ter código mais modular.

  4. admin Diz:

    A virtude está no meio. Se soubermos que se vão repetir muitos valores valerá certamente aproveitar a cache dos _SINGLE_READ. Há que ter em conta que há algumas funções _SINGLE_READ que só fazem cache da última entrada (T001_SINGLE_READ por exemplo) e por isso só serão óptimas se os vários registos estiverem ordenados pela chave da tabela a ler. Mas certamente haverão exemplos em que o FOR ALL ENTRIES se mostre mais adequado.

  5. Esperança Diz:

    Não consigo perceber porque é que a virtude estará no meio. Qual é a desvantagem de se usar o FOR ALL ENTRIES?

  6. admin Diz:

    Bruno,

    Há casos em que não dá para usar o FOR ALL ENTRIES. Imagina o seguinte cenário:

    Estás num user-exit que recebe uma tabela interna com um registo da VBAK. Sabes que esse user-exit vai corre dezenas ou centenas de vezes. lá dentro precisas de aceder a informação da KNA1 referente ao VBAK-KUNNR.

    Neste caso não podes fazer FOR ALL ENTRIES porque só recebes um registo da VBAK de cada vez.

    Se usares SELECT SINGLE para obter a KNA1 vais fazer uma chamada à base de dados de cada vez que o user-exit correr. Se em vez disso usares o FM KNA1_SINGLE_READ, como este FM faz cache das KNA1 já lidas, só efectuará uma chamada à base de dados uma vez por cada KUNNR diferente.

    Assim, com o KNA1_SINGLE_READ, no caso de uma factura VBAK com 100 itens farás 1 chamada à base de dados em vez de 100.

Deixe um comentário


About Abapinho
Abapinho runs on WordPress
Articles (RSS) e Comments (RSS).