Guia de introdução
Aplicação de técnicas básicas e conceitos
Trabalhar com classes locais
Ler dados do banco de dados
Trabalhar com objetos de dados estruturados
Trabalhar com tabelas internas complexas
Implementar atualizações do banco de dados utilizando business objects
Descrição do modelo de programação de aplicativos ABAP RESTful

Implementar instruções SELECT básicas

Objectives

After completing this lesson, you will be able to:
  • Descreva os recursos básicos do ABAP SQL.
  • Ler valores individuais do banco de dados.

Sintaxe básica do ABAP SQL

Linguagem de consulta estruturada (SQL)

Todos os sistemas de banco de dados relacionais usam uma variante do Structured Query Language (SQL) para permitir que você trabalhe com eles. O SQL padrão consiste em três componentes principais:

Linguagem de manipulação de dados (DML)
O DML é composto pelas instruções de que você precisa para trabalhar com informações em tabelas de banco de dados. Estes são INSERT, para adicionar novos registros, SELECT, para ler dados, UPDATE, para modificar registros existentes e DELETE, para eliminar conteúdos de tabela. Essas instruções são refletidas no ABAP na forma de ABAP SQL.
Linguagem de definição de dados (DDL)
A linguagem de definição de dados fornece comandos que permitem criar e excluir tabelas de banco de dados e outros artefatos de banco de dados, como esquemas, índices de tabela e visões. Em um sistema da SAP, você executa essas tarefas usando editores dedicados do ADT, não com programas ABAP. Um exemplo é o editor para definições de tabela de banco de dados que vimos anteriormente.
Linguagem de controle de dados (DCL)
A linguagem de controle de dados é utilizada no SQL para restringir o acesso aos dados no banco de dados para um determinado usuário. Ela não é utilizada em sua forma clássica no ABAP, uma vez que os usuários no nível do banco de dados não correspondem um a um com os usuários finais. Consequentemente, o ABAP tem seu próprio conceito de autorização.

Arquitetura ABAP SQL

No passado, os sistemas da SAP tinham que suportar uma variedade de plataformas de banco de dados, e cada plataforma tinha uma implementação ligeiramente diferente do padrão SQL. Isso significava que cada plataforma precisava de comandos ligeiramente diferentes para realizar uma tarefa específica. Para evitar que o código ABAP seja específico do banco de dados, a SAP inventou o ABAP SQL ou o Open SQL como era chamado originalmente.

Nota

A alteração de nome do Open SQL e do ABAP SQL também ilustra que, como fora da versão 7.53, o ABAP só suporta o SAP HANA como SGBD.

ABAP SQL é um conjunto abstrato de comandos SQL implementados no nível ABAP e integrados à linguagem ABAP. No momento da execução, o ABAP SQL é convertido em uma variante do SQL que o banco de dados entende. Essa variante é chamada Native SQL para distingui-la do ABAP SQL, a variante SQL integrada ao ABAP. A tradução do ABAP SQL para o Native SQL ocorre na interface do banco de dados, um componente do sistema ABAP que consiste em uma parte geral e uma biblioteca específica do banco de dados.

Embora as versões mais recentes do ABAP suportem apenas o SAP HANA como SGBD, a SAP ainda manteve o conceito de ABAP SQL e a interface de banco de dados. Isso se deve aos seguintes motivos:

Compatibilidade de arquitetura
O ABAP SQL e a interface do banco de dados são parte integrante da arquitetura do sistema.
Compatibilidade de código
A codificação ABAP SQL de produtos SAP anteriores (incluindo desenvolvimento específico do cliente) deve ser executada sem efeitos colaterais nos ambientes ABAP modernos somente SAP HANA.
Tarefas da interface de banco de dados
A interface do banco de dados não traduz apenas instruções; ela também é responsável por tarefas específicas do ABAP, como, por exemplo, o processamento automático de mandantes.

Leitura de registro individual do banco de dados

A instrução SELECT no ABAP

Para ler dados do banco de dados, você utiliza a instrução SELECT.

Quando você escreve uma instrução SELECT no ABAP SQL, a verificação de sintaxe compara o que você escreveu com a definição das tabelas e visões. Se você tentar endereçar tabelas, visões, ou campos que não existem, ocorrerá um erro de sintaxe.

A sintaxe básica da instrução SELECT contém várias seções, chamadas de cláusulas, e sempre segue o padrão na figura, A instrução SELECT no ABAP. As cláusulas mais importantes de uma instrução SELECT são as seguintes:

FROM
Na cláusula FROM da instrução SELECT, você especifica a fonte de dados a partir da qual deseja ler. Pode ser uma tabela de banco de dados ou uma visão. Técnicas SQL especiais permitem combinar dados de várias fontes na mesma instrução SELECT.
FIELDS
Na cláusula FIELDS da instrução SELECT, você lista as colunas da tabela de banco de dados que deseja ler. As colunas na lista devem ser separadas por vírgulas. Se quiser ler toda a linha da tabela, você pode especificar FIELDS * em vez de uma lista de colunas. No entanto, considere que isso pode fazer com que o banco de dados funcione consideravelmente mais do que apenas ler as colunas necessárias.
WHERE

Na cláusula WHERE, você pode indicar uma condição que descreva quais linhas da tabela serão lidas. Por exemplo, a condição WHERE carrier_id = 'LH' significa que só serão lidas as linhas (nas quais a coluna CARRIER_D contém o valor LH).

A cláusula WHERE pode conter várias condições ligadas aos operadores AND e OR. Por exemplo, WHERE carrier_id = 'LH' e connection_id = '0400' retornariam os dados da conexão de voo LH 0400. Você também pode negar condições utilizando NOT. A cláusula WHERE é a única cláusula opcional. Contudo, considere que, sem uma cláusula WHERE, você lê todos os dados da tabela ou se a tabela tem um campo de mandante - todos os dados que pertencem ao mandante de logon do usuário. SELECTs sem uma cláusula WHERE podem causar problemas de performance graves e devem ser evitados.

INTO
A cláusula INTO especifica a variável ou variáveis no programa ABAP em que os dados devem ser colocados. Normalmente, esta é uma estrutura ou uma tabela interna e, idealmente, deve ter a mesma sequência de componentes que a lista de colunas na cláusula FIELDS.

Nota

Você verá outras formas de sintaxe SQL no ABAP. Elas são mais antigas e foram mantidas para garantir compatibilidade. Você deve se acostumar a usar a sintaxe moderna, pois ela fornece muito mais funções e recursos do que a forma antiga.

A figura, Exemplo 1: leitura de campo individual de registro individual, ilustra uma instrução SELECT que lê um único valor do banco de dados. A cláusula FROM indica que a instrução lê a partir da tabela de banco de dados /DMO/CONNECTION. A opção SINGLE, após a palavra-chave SELECT, indica que somente uma linha (um único registro) é lida. Esta linha é identificada na cláusula WHERE fornecendo valores de filtro de chave para os campos-chave carrier_id e connection_id. Considere que a interface de banco de dados irá adicionar um filtro no mandante de campo-chave restante.

A cláusula FIELDS lista somente uma coluna da tabela: coluna AIRPORT_FROM_ID.

A cláusula INTO deve corresponder ao resto da instrução. Em nosso exemplo, isso especifica a variável airport_from_id como objeto de destino, um objeto de dados escalar de tipo idêntico ao campo de tabela airport_from_id.

Nota

O arroba (@) identifica airport_from_id como o nome de um objeto de dados ABAP. É obrigatório para todas as variáveis e constantes que você usa em uma instrução ABAP SQL. É necessário evitar ambiguidades se, por exemplo, um objeto de dados e um campo de tabela tiverem o mesmo nome.

A figura, Exemplo 2: leitura de vários campos de registro individual, ilustra uma instrução SELECT que lê dois valores do mesmo registro do banco de dados.

Desta vez, a cláusula FIELDS lista duas colunas da tabela; coluna AIRPORT_FROM_ID e coluna AIRPORT_TO_ID.

Para corresponder a isso, a cláusula INTO especifica as variáveis airport_from_id e airport_to_id como objetos de destino. Eles são separados por uma vírgula e cercados por pares de colchetes para deixar claro que, juntos, eles formam o destino da instrução SELECT.

Quando você implementa uma instrução SELECT, deve considerar sempre que não pode existir nenhum resultado, porque a tabela de banco de dados não contém dados ou porque não contém linhas que cumpram as condições na cláusula WHERE. No exemplo da figura acima, a tabela de banco de dados não contém uma linha com carrier_id = 'XX' e connection_id = '1234'.

O ABAP SQL usa o campo de sistema SY-SUBRC para indicar uma execução com êxito ou sem êxito de uma instrução. O campo do sistema SY-SUBRC é do tipo número inteiro. O valor inicial 0 indica sempre uma execução com êxito. Se, após uma instrução SELECT, SY-SUBRC contiver o valor 4, isso indica que o banco de dados retornou um resultado em branco.

Se o banco de dados retornar um resultado vazio, o ABAP SQL NÃO toca na variável de destino após INTO!

Em particular, a variável de destino não é inicializada em caso de erro.

Recomenda-se que você avalie o conteúdo do campo do sistema sy-subrc imediatamente após cada instrução SELECT.

Experimente: SELECT Exemplos

  1. Como no primeiro exercício deste curso, crie uma nova classe global que implemente a interface IF_OO_ADT_CLASSRUN.
  2. Copie o seguinte snippet de código para a parte de implementação do método if_oo_adt_classrun~main( ):
    Code Snippet
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
    DATA airport_from_id TYPE /DMO/airport_from_id. DATA airport_to_id TYPE /DMO/airport_to_id. DATA airports TYPE TABLE OF /DMO/airport_from_id. * Example 1: Single field from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO @airport_from_id. out->write( `----------` ). out->write( `Example 1:` ). out->write( |Flight LH 400 departs from { airport_from_id }.| ). * Example 2: Multiple Fields from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO ( @airport_from_id, @airport_to_id ). out->write( `----------` ). out->write( `Example 2:` ). out->write( |Flight LH 400 flies from { airport_from_id } to { airport_to_id }| ). * Example 3: Empty Result and sy-subrc ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'XX' AND connection_id = '1234' INTO @airport_from_id. IF sy-subrc = 0. out->write( `----------` ). out->write( `Example 3:` ). out->write( |Flight XX 1234 departs from { airport_from_id }.| ). ELSE. out->write( `----------` ). out->write( `Example 3:` ). out->write( |There is no flight XX 1234, but still airport_from_id = { airport_from_id }!| ). ENDIF.
  3. Pressione CTRL + F3 para ativar a classe e F9 para executá-la como um aplicativo de console.
  4. Analise a saída do console. Depurar o programa, brincar com o código-fonte para se familiarizar com os conceitos.

Ler dados de uma tabela de banco de dados

Neste exercício, você amplia sua classe local com atributos para o aeroporto de partida e o aeroporto de destino e lê os valores para esses atributos a partir de uma tabela de banco de dados.

Modelo:

  • /LRN/CL_S4D400_CLS_CONSTRUCTOR (classe global)

Solução:

  • /LRN/CL_S4D400_DBS_SELECT (classe global)

Tarefa 1: Copiar modelo

Copie a classe modelo. Como alternativa, copie sua solução do exercício anterior.

Etapas

  1. Copie a classe /LRN/CL_S4D400_CLS_CONSTRUCTOR para uma classe em seu próprio pacote (nome sugerido: ZCL_##_SELECT, onde ## representa seu número de grupo).

    1. Abra o texto fonte da classe global /LRN/CL_S4D400_CLS_CONSTRUCTOR.

    2. Vincule a visão Explorador de projetos ao editor.

    3. Na visão Explorador de projetos, clique com o botão direito do mouse na classe /LRN/CL_S4D400_CLS_CONSTRUCTOR para abrir o menu de contexto.

    4. No menu de contexto, selecione Duplicar ....

    5. Insira o nome do seu pacote no campo Pacote. No campo Nome, insira o nome ZCL_##_SELECT, onde ## representa seu número de grupo.

    6. Ajuste a descrição e selecione Seguinte.

    7. Confirme a ordem de transporte e selecione Concluir.

Tarefa 2: Declarar atributos adicionais

Amplie a classe local lcl_connection com os atributos de instância privados airport_from_id e airport_to_id. Adicione algumas saídas para os novos atributos à implementação do método get_output.

Nota

Os novos atributos ainda não estão preenchidos. Para preenchê-los, adicionaremos uma instrução SELECT ao construtor em uma das próximas tarefas deste exercício.

Etapas

  1. Mude para a classe local lcl_connection.

    1. Na classe global, selecione Tipos locais.

  2. Adicione os seguintes atributos privados à definição de classe:

    Atributos

    Nome do atributoEscopoTipo de dados
    airport_from_idinstância/DMO/AIRPORT_FROM_ID
    airport_to_idinstância/DMO/AIRPORT_TO_ID
    1. Ajuste o código da seguinte forma:

      Code Snippet
      12345678910
      PRIVATE SECTION. DATA carrier_id TYPE /dmo/carrier_id. DATA connection_id TYPE /dmo/connection_id. DATA airport_from_id TYPE /dmo/airport_from_id. DATA airport_to_id TYPE /dmo/airport_to_id. ENDCLASS.
  3. Amplie a implementação do método get_output. Anexar mais modelos de cadeia ao parâmetro de retorno r_output. Incorpore os novos atributos como expressões nos modelos de cadeia.

    1. Navegue para a implementação do método get_output.

    2. Ajuste o código da seguinte forma:

      Code Snippet
      1234567
      APPEND |--------------------------------| TO r_output. APPEND |Carrier: { carrier_id }| TO r_output. APPEND |Connection: { connection_id }| TO r_output. APPEND |Departure: { airport_from_id }| TO r_output. APPEND |Destination: { airport_to_id }| TO r_output.
  4. Ative a classe. Execute-o e analise a saída do console.

    1. Pressione Ctrl + F3 para ativar a classe.

    2. Pressione F9 para executar a classe.

Tarefa 3: Analisar a tabela de banco de dados

Analise a definição da tabela de banco de dados /DMO/CONNECTION.

Etapas

  1. Abra o objeto de desenvolvimento que contém a definição da tabela de banco de dados /DMO/CONNECTION.

    1. Na barra de ferramentas eclipse, selecione Abrir objeto de desenvolvimento ABAP ou pressione Ctrl + Shift + A.

    2. No campo de entrada, insira /dmo/con como cadeia de pesquisa.

    3. Na lista de itens correspondentes, clique em /DMO/CONNECTION (Tabela de banco de dados) e selecione OK.

  2. Abra as informações do elemento (F2) para a tabela de banco de dados /DMO/CONNECTION.

    1. Clique em /dmo/connection após a palavra-chave define table e pressione F2 para exibir as informações do elemento.

Tarefa 4: Ler dados do banco de dados

No construtor de método da classe local lcl_connection, implemente uma instrução SELECT que lê valores para os novos atributos a partir da tabela de banco de dados /DMO/CONNECTION.

Etapas

  1. Retorne à classe local lcl_connection em sua classe global.

    1. Na visão do editor do Eclipse, abra a guia ZCL_##_SELECT.

    2. Na classe global, selecione Tipos locais.

  2. Navegue para a implementação do construtor de métodos.

    1. Procure a linha de código METHOD constructor..

  3. Após a instrução ENDIF., adicione uma instrução SELECT que lê um único registro da tabela de banco de dados /DMO/CONNECTION.

    1. Ajuste o código da seguinte forma:

      Code Snippet
      123456789
      IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF. SELECT SINGLE FROM /dmo/connection
  4. Implemente a cláusula FIELDS. Leia os campos de tabela airport_from_id e airport_to_id.

    Dica

    Utilize o preenchimento automático (Ctrl + espaço) para inserir os nomes dos campos.
    1. Após FROM /DMO/CONNECTION, insira FIELDS.

    2. Após um espaço em branco, pressione Ctrl + Espaço e selecione airport_from_id.

    3. Após uma vírgula e um espaço em branco, pressione Ctrl + espaço novamente e selecione airport_to_id.

    4. A cláusula FIELDS completa deve ter o seguinte aspecto:

      Code Snippet
      123
      FIELDS airport_from_id, airport_to_id
  5. Implemente a condição WHERE. Restrinja todos os campos-chave da tabela de banco de dados (exceto o campo de mandante) com os valores dos parâmetros de importação i_carrier_id e i_connection_id. Não se esqueça de escapar dos parâmetros com prefixo @.

    Dica

    Utilize o preenchimento automático (Ctrl + espaço) para inserir os nomes dos elementos e dos parâmetros.
    1. Adicione o seguinte código após a cláusula FIELDS:

      Code Snippet
      1234
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id
  6. Implemente a cláusula INTO. Arquive o resultado SELECT nos atributos airport_from_id e airport_to_id. Não se esqueça de ignorar os atributos com o prefixo @.

    Dica

    Utilize o preenchimento automático (Ctrl + espaço) para inserir os nomes dos atributos.
    1. Ajuste o código da seguinte forma:

      Code Snippet
      123456
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
    2. A instrução SELECT completa deve ter o seguinte aspecto:

      Code Snippet
      12345678
      SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
  7. Implemente o tratamento de erros após a instrução SELECT. Verifique o conteúdo do campo do sistema sy-subrc. Se não for igual a zero, crie a exceção CX_ABAP_INVALID_VALUE.

    1. Adicione o seguinte código após a instrução SELECT:

      Code Snippet
      12345
      IF sy-subrc <> 0. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF.
  8. Ative a classe. Execute-o e analise a saída do console. Verifique se a saída para os novos atributos exibe dados.

    1. Pressione Ctrl + F3 para ativar a classe.

    2. Pressione F9 para executar a classe.