Ir para o conteúdo

JOINs em ABAP SQL

Os JOINs permitem combinar dados de múltiplas tabelas numa única consulta.


🔹 Tipos de JOIN

Tipo Descrição
INNER JOIN Retorna apenas registos que existem em ambas as tabelas
LEFT OUTER JOIN Retorna todos da esquerda + correspondentes da direita
RIGHT OUTER JOIN Retorna todos da direita + correspondentes da esquerda

Nota

ABAP SQL suporta principalmente INNER JOIN e LEFT OUTER JOIN.


🔹 INNER JOIN

Exemplo 1: Voos com Nome da Companhia

REPORT z_inner_join_demo.

DATA: BEGIN OF ls_flight,
        carrid   TYPE s_carr_id,
        connid   TYPE s_conn_id,
        carrname TYPE s_carrname,
        fldate   TYPE s_date,
        price    TYPE s_price,
      END OF ls_flight.

DATA lt_flights LIKE TABLE OF ls_flight.

START-OF-SELECTION.

  " Juntar tabelas SFLIGHT (voos) e SCARR (companhias)
  SELECT a~carrid,
         a~connid,
         b~carrname,
         a~fldate,
         a~price
    FROM sflight AS a
    INNER JOIN scarr AS b ON a~carrid = b~carrid
    INTO TABLE @lt_flights
    WHERE a~carrid = 'LH'
    UP TO 20 ROWS.

  LOOP AT lt_flights INTO ls_flight.
    WRITE: / ls_flight-carrid,
             ls_flight-connid,
             ls_flight-carrname,
             ls_flight-fldate,
             ls_flight-price.
  ENDLOOP.

Exemplo 2: Conexões com Aeroportos

" Juntar SPFLI (conexões) com T005T (países)
SELECT a~carrid,
       a~connid,
       a~cityfrom,
       a~cityto,
       b~landx AS pais
  FROM spfli AS a
  INNER JOIN t005t AS b ON a~countryfr = b~land1
  INTO TABLE @DATA(lt_connections)
  WHERE b~spras = @sy-langu
  UP TO 50 ROWS.

🔹 LEFT OUTER JOIN

Retorna todos os registos da tabela à esquerda, mesmo que não haja correspondência na direita.

REPORT z_left_join_demo.

DATA: BEGIN OF ls_result,
        carrid   TYPE s_carr_id,
        carrname TYPE s_carrname,
        connid   TYPE s_conn_id,
        cityfrom TYPE s_from_cit,
        cityto   TYPE s_to_city,
      END OF ls_result.

DATA lt_results LIKE TABLE OF ls_result.

START-OF-SELECTION.

  " Buscar todas as companhias, mesmo que não tenham conexões
  SELECT a~carrid,
         a~carrname,
         b~connid,
         b~cityfrom,
         b~cityto
    FROM scarr AS a
    LEFT OUTER JOIN spfli AS b ON a~carrid = b~carrid
    INTO TABLE @lt_results
    UP TO 100 ROWS.

  LOOP AT lt_results INTO ls_result.
    WRITE: / ls_result-carrid,
             ls_result-carrname,
             ls_result-connid.
  ENDLOOP.

Uso

Use LEFT OUTER JOIN quando precisar de todos os registos da primeira tabela, independentemente de existirem na segunda.


🔹 JOIN com Múltiplas Tabelas

Pode juntar 3 ou mais tabelas:

" Juntar SFLIGHT + SPFLI + SCARR
SELECT f~carrid,
       c~carrname,
       f~connid,
       p~cityfrom,
       p~cityto,
       f~fldate,
       f~price,
       f~currency
  FROM sflight AS f
  INNER JOIN spfli AS p ON f~carrid = p~carrid
                       AND f~connid = p~connid
  INNER JOIN scarr AS c ON f~carrid = c~carrid
  INTO TABLE @DATA(lt_full_info)
  WHERE f~carrid = 'LH'
  UP TO 20 ROWS.

🔹 JOIN com Condições Complexas

" JOIN com múltiplas condições
SELECT a~vbeln,
       a~kunnr,
       b~name1,
       a~netwr
  FROM vbak AS a
  INNER JOIN kna1 AS b ON a~kunnr = b~kunnr
  INTO TABLE @DATA(lt_orders)
  WHERE a~erdat >= '20240101'
    AND a~auart = 'OR'
    AND b~land1 = 'PT'.

🔹 Comparação: JOIN vs FOR ALL ENTRIES

❌ Evitar (SELECT em LOOP)

" Má prática - múltiplas queries
SELECT * FROM scarr INTO TABLE @DATA(lt_carriers).

LOOP AT lt_carriers INTO DATA(ls_carrier).
  SELECT * FROM spfli
    INTO TABLE @DATA(lt_temp)
    WHERE carrid = @ls_carrier-carrid.
  " Processamento...
ENDLOOP.

✅ Opção 1: INNER JOIN

" Boa prática - uma única query
SELECT a~carrid,
       a~carrname,
       b~connid,
       b~cityfrom
  FROM scarr AS a
  INNER JOIN spfli AS b ON a~carrid = b~carrid
  INTO TABLE @DATA(lt_results).

✅ Opção 2: FOR ALL ENTRIES

" Alternativa quando JOIN não é possível
SELECT * FROM scarr INTO TABLE @DATA(lt_carriers) UP TO 100 ROWS.

IF lt_carriers IS NOT INITIAL.
  SELECT * FROM spfli
    INTO TABLE @DATA(lt_connections)
    FOR ALL ENTRIES IN @lt_carriers
    WHERE carrid = @lt_carriers-carrid.
ENDIF.

🔹 Exemplo Completo: Relatório de Voos

*&---------------------------------------------------------------------*
*& Report Z_JOIN_RELATORIO_VOOS
*&---------------------------------------------------------------------*
REPORT z_join_relatorio_voos.

PARAMETERS: p_carrid TYPE s_carr_id DEFAULT 'LH',
            p_datum  TYPE s_date DEFAULT sy-datum.

DATA: BEGIN OF ls_voo,
        carrid   TYPE s_carr_id,
        carrname TYPE s_carrname,
        connid   TYPE s_conn_id,
        cityfrom TYPE s_from_cit,
        cityto   TYPE s_to_city,
        fldate   TYPE s_date,
        price    TYPE s_price,
        currency TYPE s_currcode,
        seats    TYPE s_seatsmax,
      END OF ls_voo.

DATA lt_voos LIKE TABLE OF ls_voo.

START-OF-SELECTION.

  " JOIN triplo: SFLIGHT + SPFLI + SCARR
  SELECT f~carrid,
         c~carrname,
         f~connid,
         p~cityfrom,
         p~cityto,
         f~fldate,
         f~price,
         f~currency,
         f~seatsmax
    FROM sflight AS f
    INNER JOIN spfli AS p ON f~carrid = p~carrid
                         AND f~connid = p~connid
    INNER JOIN scarr AS c ON f~carrid = c~carrid
    INTO TABLE @lt_voos
    WHERE f~carrid = @p_carrid
      AND f~fldate >= @p_datum
    ORDER BY f~fldate ASCENDING.

  IF sy-subrc = 0.
    " Cabeçalho
    WRITE: / 'Companhia:', p_carrid.
    SKIP.
    WRITE: / 'Ligação', 12 'De', 25 'Para', 40 'Data', 55 'Preço', 70 'Lugares'.
    ULINE.

    " Dados
    LOOP AT lt_voos INTO ls_voo.
      WRITE: / ls_voo-connid,
               12 ls_voo-cityfrom,
               25 ls_voo-cityto,
               40 ls_voo-fldate,
               55 ls_voo-price,
               65 ls_voo-currency,
               70 ls_voo-seats.
    ENDLOOP.

    SKIP.
    WRITE: / |Total de voos: { lines( lt_voos ) }|.
  ELSE.
    WRITE: / 'Nenhum voo encontrado para os critérios selecionados.'.
  ENDIF.

💡 Boas Práticas

✅ Fazer ❌ Evitar
Usar INNER JOIN para performance SELECT em LOOP
Especificar apenas campos necessários JOIN de muitas tabelas sem necessidade
Usar aliases (AS a, AS b) Nomes de tabela completos
WHERE nas condições principais Filtros só no lado aplicacional
Verificar sy-subrc Assumir que dados existem

🚀 Próximo Passo

Aprenda sobre Agregações e GROUP BY para calcular totais, médias e contagens.