Objectives
After completing this lesson, you will be able to:
- Preencher tabelas internas complexas com dados.
- Acessar o conteúdo de tabelas internas complexas.
- Use tabelas internas complexas no ABAP SQL.
Preenchimento de tabela interna complexa
Como você já aprendeu, a forma mais simples de adicionar uma nova linha a uma tabela interna é a instrução APPEND com um objeto de dados cujo tipo corresponde ao tipo de linha da tabela interna. Por vezes, este objeto de dados é referido como área de trabalho.
Para tabelas internas simples, a área de trabalho usada em APPEND pode ser uma variável escalar, constante ou um literal. Para tabelas internas complexas, a área de trabalho deve ser estruturada.
No exemplo, a conexão de variável estruturada é usada para preencher conexões de tabela interna.
Em princípio, existem duas formas de declarar a conexão da área de trabalho:
- Referenciar a categoria de linha st_connection diretamente
- Referencie a categoria de linha indiretamente usando LIKE LINE OF <internal_table>.
A definição de áreas de trabalho com LIKE LINE OF tem duas vantagens:
- Ela revela o objetivo da variável estruturada como área de trabalho para a tabela interna
- Ele garante que a área de trabalho se ajuste à tabela interna, mesmo que a definição da tabela interna seja modificada
Se você não preencher a área de trabalho antes da instrução APPEND, a nova linha da tabela interna será preenchida com valores iniciais específicos de tipo.
Dica
Você obtém o mesmo resultado com a variante especial APPEND INITIAL LINE TO <internal_table>. Esta variante nem sequer necessita de uma área de trabalho.
Para preencher a área de trabalho estruturada, você pode preencher os componentes individuais ou, como pode ver no exemplo, utilizar uma expressão VALUE #( ).
Como você pode ver no exemplo, você também pode utilizar uma expressão VALUE #( ) diretamente na instrução APPEND. Neste caso, você não precisa de uma área de trabalho.
Nota
Isso pode ter um efeito positivo na ocupação geral da memória do seu programa.
Existe uma variante da expressão VALUE #( ) que você pode atribuir diretamente a uma tabela interna. Nesta variante de VALUE #( ), são utilizados pares de parênteses adicionais para separar as linhas de tabela entre si.
O exemplo de código preenche agentes de frete da tabela interna com três linhas, cada uma com um valor diferente para carrier_id e carrier_name. Como resultado disso, a coluna currency_code não é mencionada, ela é preenchida com o valor inicial específico do tipo.
Nota
Com a atribuição acima, todas as linhas de tabela existentes são removidas antes de a tabela ser preenchida com as novas linhas.
Para copiar dados entre campos com nomes idênticos de duas tabelas internas, utilize o operador CORRESPONDING. Isso funciona de forma semelhante a CORRESPONDING para estruturas: para cada linha da tabela interna de origem, o sistema cria uma nova linha na tabela interna de destino e copia dados entre campos com o mesmo nome. Os campos de origem para os quais não existe nenhum campo com nome idêntico no destino não são copiados. Os campos de destino para os quais não existe nenhum campo com nome idêntico na origem são preenchidos com valores iniciais específicos de tipo.
No exemplo, os agentes de frete da tabela interna de origem contêm três linhas. Por isso, após a avaliação, as conexões de tabela interna de destino também contêm três linhas.
Os campos carrier_id e carrier_name existem nas duas tabelas internas. Eles são copiados da origem para o destino. O campo currency_code só existe na origem. Não é copiado. Os campos connection_id, airport_from_id e airport_to_id só existem no destino. Eles são preenchidos com valores iniciais.
Nota
Se a tabela interna de destino contiver dados antes da atribuição, o sistema elimina os mesmos.
Como depurar tabelas internas complexas
Testar: preencher tabelas internas complexas
- Como está no primeiro exercício deste curso, crie uma nova classe global que implemente a interface IF_OO_ADT_CLASSRUN.
- Copie o seguinte snippet de código para a parte de implementação do método if_oo_adt_classrun~main( ):
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
TYPES: BEGIN OF st_connection,
carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.
TYPES tt_connections TYPE STANDARD TABLE OF st_connection
WITH NON-UNIQUE KEY carrier_id
connection_id.
DATA connections TYPE tt_connections.
TYPES: BEGIN OF st_carrier,
carrier_id TYPE /dmo/carrier_id,
carrier_name TYPE /dmo/carrier_name,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.
TYPES tt_carriers TYPE STANDARD TABLE OF st_carrier
WITH NON-UNIQUE KEY carrier_id.
DATA carriers TYPE tt_carriers.
* Example 1: APPEND with structured data object (work area)
**********************************************************************
* DATA connection TYPE st_connection.
" Declare the work area with LIKE LINE OF
DATA connection LIKE LINE OF connections.
* connection-carrier_id = 'NN'.
* connection-connection_id = '1234'.
* connection-airport_from_id = 'ABC'.
* connection-airport_to_id = 'XYZ'.
* connection-carrier_name = 'My Airline'.
" Use VALUE #( ) instead assignment to individual components
connection = VALUE #( carrier_id = 'NN'
connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline' ).
APPEND connection TO connections.
out->write( `--------------------------------` ).
out->write( `Example 1: APPEND with Work Area` ).
out->write( connections ).
* Example 2: APPEND with VALUE #( ) expression
**********************************************************************
APPEND VALUE #( carrier_id = 'NN'
connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline'
)
TO connections.
out->write( `----------------------------` ).
out->write( `Example 2: Append with VALUE` ).
out->write( connections ).
* Example 3: Filling an Internal Table with Several Rows
**********************************************************************
carriers = VALUE #( ( carrier_id = 'AA' carrier_name = 'American Airlines' )
( carrier_id = 'JL' carrier_name = 'Japan Airlines' )
( carrier_id = 'SQ' carrier_name = 'Singapore Airlines')
).
out->write( `-----------------------------------------` ).
out->write( `Example 3: Fill Internal Table with VALUE` ).
out->write( carriers ).
* Example 4: Filling one Internal Table from Another
**********************************************************************
connections = CORRESPONDING #( carriers ).
out->write( `--------------------------------------------` ).
out->write( `Example 4: CORRESPONDING for Internal Tables` ).
out->write( data = carriers
name = `Source Table CARRIERS:`).
out->write( data = connections
name = `Target Table CONNECTIONS:`).
- Pressione CTRL + F3 no teclado para ativar a classe e F9 para executar o aplicativo do console.
- Analise a saída do console. Depurar o programa, brincar com o código-fonte para se familiarizar com os conceitos.
Acesso a tabelas internas complexas
Anteriormente, neste curso, você aprendeu a recuperar uma única linha de uma tabela interna simples usando uma expressão de tabela interna. Em seguida, utilizamos um índice de acesso, ou seja, identificamos a linha através de sua posição na tabela interna. Este acesso ao índice funciona para tabelas internas complexas da mesma forma. No entanto, para tabelas internas complexas, as expressões de tabela interna com acesso por chave se tornam importantes, onde você identifica a linha por meio do respectivo conteúdo.
Nota
Embora isso seja chamado de acesso por chave, você pode usar quaisquer campos para a seleção, não só campos-chave da tabela interna. Se mais de uma linha cumprir o requisito, as tabelas STANDARD retornam a primeira linha, ou seja, a linha com o índice mais baixo.
O exemplo lê uma única linha de conexões de tabela interna. A chave desta tabela interna é composta por campos, carrier_id e connection_id, mas o acesso por chave utiliza airport_from_id e airport_to_id para identificar a linha. A tabela Interna contém duas conexões do aeroporto SFO ao SIN, de modo que a primeira delas é retornada.
Lembre-se de que o tempo de execução ABAP cria a exceção CX_SY_ITAB_LINE_NOT_FOUND se nenhuma das linhas cumprir o requisito. Trate esta exceção em uma estrutura TRY … CATCH … ENDTRY para evitar erros em tempo de execução
Para processar várias linhas de uma tabela interna indicando campos, você utiliza LOOP AT <tabela interna> INTO <destino> WHERE <condição>. A condição WHERE pode conter qualquer número de expressões constituintes unidas usando AND e OR. Dentro das expressões, você pode utilizar não só o operador igual (=), mas também os operadores >, >=, <, <=, <> e BETWEEN.
Depois de ler o conteúdo de uma linha de tabela em uma área de trabalho, às vezes você quer gravar modificações da área de trabalho de volta para a tabela interna. Uma forma de fazer isso é a instrução MODIFY TABLE.
Esta instrução é um acesso chave porque o sistema utiliza o conteúdo dos campos-chave na área de trabalho para identificar a linha de tabela que precisa ser modificada. Em seguida, ele sobregrava esta linha de tabela com o conteúdo da área de trabalho.
No exemplo, o agente de frete da área de trabalho contém o valor 'JL' no campo-chave, carrier_id. Com base nesse valor, o sistema identifica a segunda linha a ser atualizada. Esta linha é então atualizada com os valores da área de trabalho.
Nota
Você só pode modificar campos não chave com MODIFY TABLE. A instrução não suporta modificações em campos-chave.
A instrução MODIFY (sem palavra-chave TABLE!) O não distingue entre campos-chave e campos não chave. Ele sobregrava toda a linha da tabela com novos valores da área de trabalho. Esta instrução é considerada um acesso por índice porque a linha a ser atualizada é identificada pela sua posição na tabela interna. Normalmente, o índice é especificado explicitamente usando a adição INDEX seguido por um argumento inteiro (literal, constante, variável, expressão).
Nota
Também existe uma variante especial sem adição de INDEX. Discutiremos esta variante em seguida.
No exemplo, a instrução MODIFY utiliza o suplemento INDEX para endereçar a primeira linha da tabela. Nesta linha, todos os campos são sobregravados com os valores da área de trabalho, mesmo o campo-chave carrier_id.
Muitas vezes, haverá momentos em que você precisa modificar o conteúdo de várias linhas de uma tabela interna, ou talvez até mesmo todas elas. Para isso, você implementa um loop sobre a tabela, que coloca cada linha que você precisa modificar sucessivamente em uma área de trabalho. No loop, você primeiro modifica o conteúdo da área de trabalho e, em seguida, escreve as modificações de volta na tabela interna utilizando a instrução MODIFY.
Nota
Se você não gravar suas modificações de volta na tabela, as modificações serão perdidas quando a área de trabalho for preenchida com os dados da linha seguinte.
No exemplo, o loop lê todas as linhas de suportes de tabela interna para as quais o campo currency_code ainda não está preenchido. Este é o caso para as duas últimas linhas. Para cada uma dessas linhas, o programa substitui o valor inicial no campo currency_code pelo novo valor 'USD'. Por fim, ele utiliza a instrução MODIFY para sobregravar a linha atual com os valores atualizados.
Em vez de indicar o índice explicitamente, o exemplo de código utiliza uma forma breve da instrução MODIFY onde o suplemento INDEX está em falta. Esta forma breve só é permitida entre LOOP … ENDLOOP. Só aí o sistema pode atualizar implicitamente a linha em que está trabalhando atualmente.
Se você utilizar MODIFY sem INDEX fora de LOOP…ENDLOOP, o sistema não sabe qual linha modificar e aciona um erro em tempo de execução não interceptável. Para evitar esses erros em tempo de execução, certifique-se de que não ignora o aviso relacionado da verificação de sintaxe.
Testar: acesso a tabelas internas complexas
- Tal como acontece com o primeiro exercício deste curso, crie uma nova classe global que implemente a interface IF_OO_ADT_CLASSRUN.
- Copie o seguinte snippet de código para a parte de implementação do método if_oo_adt_classrun~main( ):
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
TYPES: BEGIN OF st_connection,
carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.
TYPES tt_connections TYPE SORTED TABLE OF st_connection
WITH NON-UNIQUE KEY carrier_id
connection_id.
DATA connections TYPE tt_connections.
DATA connection LIKE LINE OF connections.
TYPES: BEGIN OF st_carrier,
carrier_id TYPE /dmo/carrier_id,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.
DATA carriers TYPE STANDARD TABLE OF st_carrier
WITH NON-UNIQUE KEY carrier_id.
DATA carrier LIKE LINE OF carriers.
* Preparation: Fill internal tables with data
**********************************************************************
connections = VALUE #( ( carrier_id = 'JL'
connection_id = '0408'
airport_from_id = 'FRA'
airport_to_id = 'NRT'
carrier_name = 'Japan Airlines'
)
( carrier_id = 'AA'
connection_id = '0017'
airport_from_id = 'MIA'
airport_to_id = 'HAV'
carrier_name = 'American Airlines'
)
( carrier_id = 'SQ'
connection_id = '0001'
airport_from_id = 'SFO'
airport_to_id = 'SIN'
carrier_name = 'Singapore Airlines'
)
( carrier_id = 'UA'
connection_id = '0078'
airport_from_id = 'SFO'
airport_to_id = 'SIN'
carrier_name = 'United Airlines'
)
).
carriers = VALUE #( ( carrier_id = 'SQ'
currency_code = ' '
)
( carrier_id = 'JL'
currency_code = ' '
)
( carrier_id = 'AA'
currency_code = ' '
)
( carrier_id = 'UA'
currency_code = ' '
)
).
* Example 1: Table Expression with Key Access
**********************************************************************
out->write( `--------------------------------------------` ).
out->write( `Example 1: Table Expressions with Key Access` ).
out->write( data = connections
name = `Internal Table CONNECTIONS: ` ).
" with key fields
connection = connections[ carrier_id = 'SQ'
connection_id = '0001' ].
out->write( data = connection
name = `CARRIER_ID = 'SQ' AND CONNECTION_ID = '001':` ).
" with non-key fields
connection = connections[ airport_from_id = 'SFO'
airport_to_id = 'SIN' ].
out->write( data = connection
name = `AIRPORT_FROM_ID = 'SFO' AND AIRPORT_TO_ID = 'SIN':` ).
* Example 2: LOOP with key access
**********************************************************************
out->write( `-------------------------------` ).
out->write( `Example 2: LOOP with Key Access` ).
LOOP AT connections INTO connection
WHERE airport_from_id <> 'MIA'.
"do something with the content of connection
out->write( data = connection
name = |This is row number { sy-tabix }: | ).
ENDLOOP.
* Example 3: MODIFY TABLE (key access)
**********************************************************************
out->write( `-----------------------------------` ).
out->write( `Example 3: MODIFY TABLE (key access` ).
out->write( data = carriers
name = `Table CARRRIERS before MODIFY TABLE:`).
carrier = carriers[ carrier_id = 'JL' ].
carrier-currency_code = 'JPY'.
MODIFY TABLE carriers FROM carrier.
out->write( data = carriers
name = `Table CARRRIERS after MODIFY TABLE:`).
* Example 4: MODIFY (index access)
**********************************************************************
out->write( `--------------------------------` ).
out->write( `Example 4: MODIFY (index access)` ).
carrier-carrier_id = 'LH'.
carrier-currency_code = 'EUR'.
MODIFY carriers FROM carrier INDEX 1.
out->write( data = carriers
name = `Table CARRRIERS after MODIFY:`).
* Example 5: MODIFY in a LOOP
**********************************************************************
out->write( `----------------------------` ).
out->write( `Example 5: MODIFY in a LOOP` ).
LOOP AT carriers INTO carrier
WHERE currency_code IS INITIAL.
carrier-currency_code = 'USD'.
MODIFY carriers FROM carrier.
ENDLOOP.
out->write( data = carriers
name = `Table CARRRIERS after the LOOP:`).
- Pressione CTRL + F3 no teclado para ativar a classe e F9 para executar o aplicativo do console.
- Analise a saída do console. Depurar o programa, brincar com o código-fonte para se familiarizar com os conceitos.
Tabelas internas complexas no ABAP SQL
A instrução ABAP SQL, SELECT, lê dados de uma tabela de banco de dados ou de uma visão CDS. Quando você utiliza a opção SINGLE, é lido exatamente um registro do banco de dados, mesmo que existam mais dados que cumpram as condições na cláusula WHERE.
Como você aprendeu anteriormente, uma forma de receber este resultado de registro individual é a variável estruturada após a palavra-chave INTO.
Se você utilizar SELECT sem SINGLE, indica que está interessado em todos os registros que correspondem às condições na cláusula WHERE. Em seguida, você deve garantir que pode realmente receber e armazenar vários registros. A maneira óbvia de fazer isso é a utilização de uma tabela interna complexa como destino da instrução SELECT. Isso é possível, mas requer a adição de TABLE entre a palavra-chave INTO e o nome da tabela interna.
No exemplo, queremos ler todos os três aeroportos relacionados a Londres e não apenas um deles. Portanto, deixamos de fora a palavra-chave SINGLE após SELECT, adicionamos a palavra-chave TABLE após INTO e usamos a tabela interna airports_full como destino da instrução SELECT.
O exemplo usa uma lista de campos explícita após FIELDS que corresponde às colunas da tabela interna airports_full. Obviamente, você também pode utilizar FIELDS *, INTO CORRESPONDING FIELDS OF TABLE e nomes de alias na lista de campos.
Este exemplo utiliza FIELDS * em vez de uma lista de campos explícita e INTO CORRESPONDING FIELDS OF TABLE em vez de INTO TABLE.
Uma vez que o tipo de linha de aeroportos de tabela interna contém somente dois componentes AirportID e Name, somente os campos com o mesmo nome são lidos do banco de dados.
Se você utilizar DATA( ) em uma instrução SELECT após o suplemento INTO TABLE, você declara inline uma tabela interna. O tipo de linha desta tabela interna é derivado da cláusula FIELDS. Para campos de tabela e elementos de visão, um nome de alias é opcional. Para expressões na cláusula FIELDS, um nome de alias é obrigatório se a cláusula INTO contiver uma declaração inline.
Nota
As declarações inline de tabelas internas só são suportadas após INTO TABLE. Você não pode utilizar declarações inline após INTO CORRESPONDING FIELDS OF TABLE.
As tabelas internas declaradas inline são sempre tabelas padrão sem uma chave. Você não pode declarar tabelas ordenadas ou hash usando declarações inline. Isso pode causar problemas de performance se você preencher a tabela interna com muitas linhas e utilizar um lote de acesso por chave.
Quando você está lendo vários registros do banco de dados, algumas técnicas SQL especiais se tornam particularmente interessantes. Uma dessas técnicas é a diretriz UNION para combinar os resultados de várias instruções SELECT.
A figura ilustra a combinação de dois resultados SELECT:
O primeiro resultado SELECT lê ID e NAME de todos os agentes de frete com CurrencyCode = 'GBP'. O segundo SELECT lê ID e NAME de todos os aeroportos com City = 'London'. O primeiro SELECT retorna um registro, o segundo SELECT retorna três registros. Em vez de recuperar esses resultados separadamente, eles são combinados em um resultado com quatro registros. É importante ressaltar que isso acontece dentro do banco de dados.
Um pré-requisito para esta técnica é, obviamente, que os dois resultados sejam compatíveis entre si, ou seja, que eles tenham o mesmo número de campos e os mesmos nomes de campo. É vantajoso, embora não seja necessário, que os tipos dos campos também sejam os mesmos.
A sintaxe ABAP SQL para este exemplo consiste em duas instruções SELECT. Cada instrução SELECT tem sua própria cláusula FROM, cláusula FIELDS e cláusula WHERE, mas só existe uma cláusula INTO no final. As duas instruções SELECT são conectadas por palavras-chave UNION ALL.
Nota
Com UNION em vez de UNION ALL, o banco de dados procuraria e eliminaria duplicatas antes de retornar o resultado. Usamos UNION ALL para evitar essa carga adicional desnecessária no banco de dados.
As duas listas de campos são compostas por três elementos, o primeiro e o segundo elemento têm nomes de alias idênticos nas duas cláusulas FIELDS. O terceiro campo não precisa de um alias porque o nome do campo é o mesmo nas duas visões CDS.
Nota
O primeiro elemento em FIELDS é um texto literal que nos permite distinguir entre companhias aéreas e aeroportos no resultado combinado.
Testar: tabelas internas no ABAP SQL
- Como no primeiro exercício deste curso, crie uma nova classe global que implemente a interface IF_OO_ADT_CLASSRUN.
- Copie o seguinte snippet de código para a parte de implementação do método if_oo_adt_classrun~main( ):
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
TYPES: BEGIN OF st_airport,
airportid TYPE /dmo/airport_id,
name TYPE /dmo/airport_name,
END OF st_airport.
TYPES tt_airports TYPE STANDARD TABLE OF st_airport
WITH NON-UNIQUE KEY airportid.
DATA airports TYPE tt_airports.
* Example 1: Structured Variables in SELECT SINGLE ... INTO ...
**********************************************************************
DATA airport_full TYPE /DMO/I_Airport.
SELECT SINGLE
FROM /DMO/I_Airport
FIELDS AirportID, Name, City, CountryCode
WHERE City = 'Zurich'
INTO @airport_full.
out->write( `-------------------------------------` ).
out->write( `Example 1: SELECT SINGLE ... INTO ...` ).
out->write( data = airport_full
name = `One of the airports in Zurich (Structure):` ).
* Example 2: Internal Tables in SELECT ... INTO TABLE ...
**********************************************************************
DATA airports_full TYPE STANDARD TABLE OF /DMO/I_Airport
WITH NON-UNIQUE KEY AirportID.
SELECT
FROM /DMO/I_Airport
FIELDS airportid, Name, City, CountryCode
WHERE City = 'London'
INTO TABLE @airports_full.
out->write( `------------------------------------` ).
out->write( `Example 2: SELECT ... INTO TABLE ...` ).
out->write( data = airports_full
name = `All airports in London (Internal Table):` ).
* Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE
**********************************************************************
SELECT
FROM /DMO/I_Airport
FIELDS *
WHERE City = 'London'
INTO CORRESPONDING FIELDS OF TABLE @airports.
out->write( `----------------------------------------------------------` ).
out->write( `Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE` ).
out->write( data = airports
name = `Internal Table AIRPORTS:` ).
* Example 4: Inline Declaration
**********************************************************************
SELECT
FROM /DMO/I_airport
FIELDS AirportID, Name AS AirportName
WHERE City = 'London'
INTO TABLE @DATA(airports_inline).
out->write( `----------------------------------------------------------` ).
out->write( `Example 4: Inline Declaration after INTO TABLE` ).
out->write( data = airports_inline
name = `Internal Table AIRPORTS_INLINE:` ).
** Example 4: ORDER BY and DISTINCT
***********************************************************************
*
* SELECT
* FROM /DMO/I_Airport
* FIELDS DISTINCT CountryCode
* ORDER BY CountryCode
* INTO TABLE @DATA(countryCodes).
*
* out->write( countryCodes ).
* Example 5: UNION (ALL)
**********************************************************************
SELECT FROM /DMO/I_Carrier
FIELDS 'Airline' AS type, AirlineID AS Id, Name
WHERE CurrencyCode = 'GBP'
UNION ALL
SELECT FROM /DMO/I_Airport
FIELDS 'Airport' AS type, AirportID AS Id, Name
WHERE City = 'London'
* ORDER BY type, Id
INTO TABLE @DATA(names).
out->write( `----------------------------------------------` ).
out->write( `Example 5: UNION ALL of Airlines and Airports ` ).
out->write( data = names
name = `ID and Name of Airlines and Airports:` ).
- Pressione CTRL + F3 no teclado para ativar a classe e F9 para executar o aplicativo do console.
- Analise a saída do console. Depurar o programa, brincar com o código-fonte para se familiarizar com os conceitos.
Utilizar uma tabela interna complexa
Neste exercício, você declara um atributo em forma de tabela, preenche o mesmo usando uma instrução SELECT e acessa o conteúdo.
Tarefa 1: Copiar modelo
Copie a classe modelo. Como alternativa, copie sua solução do exercício anterior.
Etapas
Copie a classe /LRN/CL_S4D400_STS_STRUCTURE para uma classe em seu próprio pacote (nome sugerido: ZCL_##_ITAB, onde ## representa seu número de grupo).
Abra o texto fonte da classe global /LRN/CL_S4D400_STS_STRUCTURE.
Vincule a visão Explorador de projetos ao editor.
Na visão Explorador de projetos, clique com o botão direito do mouse na classe /LRN/CL_S4D400_STS_STRUCTURE para abrir o menu de contexto.
No menu de contexto, selecione Duplicar ....
Insira o nome do seu pacote no campo Pacote. No campo Nome, insira o nome ZCL_##_ITAB, onde ## representa seu número de grupo.
Ajuste a descrição e selecione Seguinte.
Confirme a ordem de transporte e selecione Concluir.
Tarefa 2: Declarar uma tabela interna
Na classe local, declare um aeroporto de atributo estático em forma de tabela para armazenar em buffer informações detalhadas em todos os aeroportos disponíveis. Comece definindo um tipo de estrutura privada st_airport e um tipo de tabela tt_airport dentro da classe local.
Etapas
Mude para a classe local lcl_connection.
Na classe global, selecione Tipos locais.
Defina um tipo de estrutura privadast_airport com os seguintes componentes:
Componentes do tipo de estrutura st_airport:
| Nome do componente | Tipo de dados |
|---|
| AirportID | /dmo/airport_id |
| Nome | /dmo/airport_name |
Ajuste o código da seguinte forma:
1234567891011121314
TYPES:
BEGIN OF st_details,
DepartureAirport TYPE /dmo/airport_from_id,
DestinationAirport TYPE /dmo/airport_to_id,
AirlineName TYPE /dmo/carrier_name,
END OF st_details.
TYPES:
BEGIN OF st_airport,
AirportId TYPE /dmo/airport_id,
Name TYPE /dmo/airport_name,
END OF st_airport.
Defina um tipo de tabela privadatt_airport com as seguintes propriedades:
Propriedades do tipo de tabela tt_airport:
| Característica | Valor |
|---|
| Tipo de linha | st_airport |
| Forma de tabela | TABELA PADRÃO |
| Definição de chave | CHAVE DE PADRÃO NÃO ÚNICA |
Ajuste o código da seguinte forma:
12345678910
TYPES:
BEGIN OF st_airport,
AirportId TYPE /dmo/airport_id,
Name TYPE /dmo/airport_name,
END OF st_airport.
TYPES tt_airports TYPE STANDARD TABLE OF st_airport
WITH NON-UNIQUE DEFAULT KEY.
Declare um novo atributo estático privado de aeroportos e digite-o com o tipo de tabela tt_airport.
No final da definição de classe, adicione o seguinte código:
123
CLASS-DATA airports TYPE tt_airports.
Tarefa 3: Preencher o atributo estático em um construtor de classes
Defina um construtor de classe e implemente uma instrução SELECT que leia todos os aeroportos disponíveis da entidade de visão CDS /DMO/I_Airport para os aeroportos de atributo estático.
Etapas
Adicione um construtor de classe à classe local lcl_connection usando uma correção rápida.
Posicione o cursor no nome da classe e pressione Ctrl + 1.
Clique duas vezes em Gerar construtor de classes.
No construtor de classe, implemente uma instrução SELECT que leia todos os conjuntos de dados da entidade de visão CDS /DMO/I_Airport nos aeroportos de atributo estático.
Navegue para a implementação do método class_constructor.
Dentro da implementação do método, adicione o seguinte código:
12345
SELECT FROM /DMO/I_Airport
FIELDS AirportID, Name
INTO TABLE @airports.
Tarefa 4: Acessar o conteúdo da tabela interna
Use o conteúdo de tabelas internas de aeroportos no método get_output para adicionar os nomes dos aeroportos à saída.
Etapas
Navegue para a implementação do método get_output.
Prossiga da mesma maneira que você fez em exercícios anteriores.
No início do método, leia os detalhes do aeroporto de partida em uma partida do objeto de dados estruturado.
Dica
Utilize uma expressão de tabela airports[ ... ] e uma declaração inline para a partida do objeto de dados.
No início do método, adicione o seguinte código:
123
DATA(departure) = airports[ airportID = details-departureairport ].
Da mesma forma, leia os detalhes do aeroporto de destino em um destino de objeto de dados estruturado.
Ajuste o código da seguinte forma:
1234
DATA(departure) = airports[ airportID = details-departureairport ].
DATA(destination) = airports[ airportID = details-destinationairport ].
Use o nome do componente das duas estruturas para adicionar os nomes dos aeroportos à saída.
Ajuste o código da seguinte forma:
1234
APPEND |Departure: { details-departureairport } { departure-name }| TO r_output.
APPEND |Destination: { details-destinationairport } { destination-name }| TO r_output.
Opcional: omita o objeto de dados estruturado e use as expressões de tabela diretamente nos modelos de string.
Comente as linhas de código onde você preenche as estruturas partida e destino.
No modelo de cadeia, substitua departure-name por airports[ airportid = details-departureairport ]-name.
Da mesma forma, substitua destination-name por airports[ airportid = details-destinationairport ]-name.
Ative a classe. Execute-o e analise a saída do console. Verifique se a saída exibe dados para todos os atributos.
Pressione Ctrl + F3 para ativar a classe.
Pressione F9 para executar a classe.