• Inicio
  • Novedades
  • Academia SAP
  • FAQ
  • Blog
  • Contacto
S4PCADEMY_Logo
Twitter Linkedin Instagram
S4PCADEMY_Logo
Twitter Linkedin Instagram
SAP ABAP

Cómo crear una tabla y enviar datos a ODBC/base de datos remota utilizando SQL nativo con conectividad ABAP DB (ADBC)

By s4pcademy 


Recientemente tuve la tarea de enviar datos de los informes de SAP a la base de datos MS SQL, periódicamente, y también crear tablas de los informes requeridos en su base de datos MS SQL.

Siendo un desarrollador ABAP completamente novato, aprendí sobre Conectividad ABAP DB (ADBC) DDL y DML métodos, que me ayudaron a completar la tarea de forma más dinámica, en lugar de usar SQL EXEC con marcadores de posición? para cada campo

Antes de seguir adelante, me gustaría señalar lo obvio de que de ninguna manera mi enfoque es el mejor/óptimo que existe.

Entonces, comencemos el código con los siguientes objetivos:

  1. Cree un programa para obtener datos de SAP Report usando ENVIAR
  2. Crear tabla en MS SQL DB de acuerdo con los campos del informe
  3. Insertar datos en la tabla recién creada

1. Cree un programa para obtener datos de SAP Report usando ENVIAR

REPORT ZSCHEDULE.

DATA:
  CREATE_FIELDS TYPE STRING,
  CREATE_PKEY   TYPE STRING,
  INSERT_VALUES TYPE STRING,
  IT_INSERT     TYPE STRINGTAB,
  DATUM         TYPE DATUM,
  UZEIT         TYPE UZEIT.

FIELD-SYMBOLS: <LT_SALV> TYPE ANY TABLE,
               <VALUE>   TYPE ANY.

DATA:
  LS_VBAK TYPE VBAK,
  LS_VBAP TYPE VBAP.

SELECT-OPTIONS:
    SO_VKORG FOR LS_VBAK-VKORG,
    SO_VTWEG FOR LS_VBAK-VTWEG,
    SO_SPART FOR LS_VBAK-SPART,
    SO_VSTEL FOR LS_VBAP-VSTEL,
    SO_VKBUR FOR LS_VBAK-VKBUR.

START-OF-SELECTION.

TRY.

  CL_SALV_BS_RUNTIME_INFO=>SET( DISPLAY = ABAP_FALSE
                                METADATA = ABAP_TRUE
                                DATA = ABAP_TRUE ).

  SUBMIT Z_RPT_PROG
  WITH  SO_VKORG IN  SO_VKORG
  WITH  SO_VTWEG IN  SO_VTWEG
  WITH  SO_SPART IN  SO_SPART
  WITH  SO_VSTEL IN  SO_VSTEL
  WITH  SO_VKBUR IN  SO_VKBUR
    AND RETURN.

  DATA(SALV_META) = CL_SALV_BS_RUNTIME_INFO=>GET_METADATA( ).
  CL_SALV_BS_RUNTIME_INFO=>GET_DATA_REF( IMPORTING R_DATA = DATA(SALV_DATA) ).
  ASSIGN SALV_DATA->* TO <LT_SALV>.

  CL_SALV_BS_RUNTIME_INFO=>CLEAR_ALL( ).
...

He usado el formidable CL_SALV_BS_RUNTIME_INFO clase para extraer datos ALV del programa SUBMIT

2. Cree una tabla en MS SQL DB de acuerdo con los campos del informe

También he cogido el Metadatos ALV porque necesito Catálogo de campo del programa SUBMIT para crear nuestros campos DB Table

Entonces tuve que escribir una lógica para crear diferentes campos de tipo de datos en SQL, para usar en CREAR MESA Sentencia SQL nativa dinámicamente

...
  LOOP AT SALV_META-T_FCAT INTO DATA(WA_FCAT).

    REPLACE ALL OCCURRENCES OF '/' IN WA_FCAT-FIELDNAME WITH '_'. " forward slash / is considered COMMENT in SQL
    MODIFY SALV_META-T_FCAT FROM WA_FCAT TRANSPORTING FIELDNAME.

    CASE WA_FCAT-DATATYPE.
      WHEN 'CHAR'.
        CREATE_FIELDS = CREATE_FIELDS && |{ WA_FCAT-FIELDNAME } varchar({ WA_FCAT-INTLEN })|.
      WHEN 'CUKY'.
        CREATE_FIELDS = CREATE_FIELDS && |{ WA_FCAT-FIELDNAME } varchar(5)|.
      WHEN 'UNIT'.
        CREATE_FIELDS = CREATE_FIELDS && |{ WA_FCAT-FIELDNAME } varchar(3)|.
      WHEN 'DATS'.
        CREATE_FIELDS = CREATE_FIELDS && |{ WA_FCAT-FIELDNAME } date|.
      WHEN 'TIMS'.
        CREATE_FIELDS = CREATE_FIELDS && |{ WA_FCAT-FIELDNAME } time|.
      WHEN 'RAW'.
        CREATE_FIELDS = CREATE_FIELDS && |{ WA_FCAT-FIELDNAME } nvarchar(max)|.
      WHEN 'NUMC' OR 'INT4' OR 'DEC' OR 'QUAN' OR 'CURR'.
        CREATE_FIELDS = CREATE_FIELDS && |{ WA_FCAT-FIELDNAME } float|.
    ENDCASE.

    CREATE_FIELDS = CREATE_FIELDS && ','.

    IF WA_FCAT-KEY EQ 'X'.
      IF CREATE_PKEY IS NOT INITIAL.
        CREATE_PKEY = CREATE_PKEY && ','.
      ENDIF.
      CREATE_PKEY = CREATE_PKEY && |[{ WA_FCAT-FIELDNAME }]|.
    ENDIF.
  ENDLOOP.

  DATA(TABLE) = `SAP_ZREPORT`.

  IF CREATE_PKEY IS INITIAL.
    DATA(CREATE_TABLE) = |CREATE TABLE { TABLE } ( { CREATE_FIELDS } )|.
  ELSE.
    CREATE_TABLE = |CREATE TABLE { TABLE } ( { CREATE_FIELDS } PRIMARY KEY ({ CREATE_PKEY }) )|.
  ENDIF.
...

CREAR MESA La declaración SQL DDL está lista con todos los campos en el catálogo de campos, junto con las claves principales y lista para ejecutarse con ADBC EXECUTE_DDL declaración

Como estaba creando campos de tabla de base de datos SQL con nombres de campo de SAP, el cliente solicitó tener campo Descripción en la sección Comentarios de cada campo para su identificación, como el siguiente:

Así que usé ALTERAR TABLA Declaración SQL DDL para agregar Descripción en el campo Comentario

...
  LOOP AT SALV_META-T_FCAT ASSIGNING FIELD-SYMBOL(<FIELD>).
    CASE <FIELD>-DATATYPE.
      WHEN 'CHAR'.
        <FIELD>-TOOLTIP = |varchar({ <FIELD>-INTLEN })|.
      WHEN 'CUKY'.
        <FIELD>-TOOLTIP = |varchar(5)|.
      WHEN 'UNIT'.
        <FIELD>-TOOLTIP = |varchar(3)|.
      WHEN 'DATS'.
        <FIELD>-TOOLTIP = |date|.
      WHEN 'TIMS'.
        <FIELD>-TOOLTIP = |time|.
      WHEN 'RAW'.
        <FIELD>-TOOLTIP = |nvarchar(max)|.
      WHEN 'NUMC' OR 'INT4' OR 'DEC' OR 'QUAN' OR 'CURR'.
        <FIELD>-TOOLTIP = |float|.
    ENDCASE.
    REPLACE ALL OCCURRENCES OF '/'  IN <FIELD>-SELTEXT WITH '-'. " forward slash / is considered COMMENT in SQL
    IF <FIELD>-SELTEXT IS INITIAL. " COMMENT/DESCRIPTION cannot be blank in ALTER TABLE statement
      <FIELD>-SELTEXT = <FIELD>-FIELDNAME.
    ENDIF.
  ENDLOOP.

  LOOP AT SALV_META-T_FCAT INTO DATA(WA_TABLE_FIELDS).
    DATA(ALTER_TABLE) = |ALTER TABLE { TABLE } ALTER COLUMN "{ WA_TABLE_FIELDS-FIELDNAME }" { WA_TABLE_FIELDS-TOOLTIP } NULL|.
    DATA(ALTER) = |{ ALTER_TABLE } EXECUTE sp_addextendedproperty 'MS_Description', '{ WA_TABLE_FIELDS-SELTEXT }', 'Schema', 'dbo', 'table', '{ TABLE }', 'column', '{ WA_TABLE_FIELDS-FIELDNAME }';|.
   APPEND ALTER TO IT_INSERT.
  ENDLOOP.
...

Tenga en cuenta que ALTERAR TABLA Sentencia SQL DDL con MS_Descripción es solo para MS SQL y debe pasarse con el mismo orden como:

ALTER TABLE ALTER COUMN “” NULL EJECUTAR sp_addextendedproperty ‘MS_Description’, ‘‘, ‘Schema’, ‘‘, ‘table’, ‘‘, ‘column’, ‘‘;

y he anexado ALTERAR declaraciones en la tabla interna IT_INSERT

ahora es el momento de la ejecución de SQL nativo declaraciones usando ADBC

  DATA(DBCONN) = CL_SQL_CONNECTION=>GET_CONNECTION( 'SQL' ).
  DATA(CREATE_STATEMENT) = DBCONN->CREATE_STATEMENT( ).

  CREATE_STATEMENT->EXECUTE_DDL( CREATE_TABLE ). " create table statement

  LOOP AT IT_INSERT INTO DATA(ROW).
    CREATE_STATEMENT->EXECUTE_DDL( ROW ). " alter table statment
  ENDLOOP.

  DBCONN->COMMIT( ).
  DBCONN->CLOSE( ).

3. Empuje los datos en la tabla recién creada

Así que ahora mi tabla está creada en el Base de datos ODBCque se muestra en la captura de pantalla anterior, no necesito CREAR MESA y ALTERAR TABLA declaraciones porque fue un proceso de una sola vez, ya que voy a ejecutar este programa a tiempo para enviar datos a la base de datos remota

La parte complicada fue donde tuve que crear INSERTAR Declaración SQL DML con mis valores completos de estructura/área de trabajo, en consecuencia, usando bucle anidado y ASSIGN COMPONENT

y tuve que escribir lógica para manejar el campo FECHA y HORA para SQL porque SQL usa el formato ISO para FECHA y HORA

...
  LOOP AT <LT_SALV> ASSIGNING FIELD-SYMBOL(<WA>).

    LOOP AT SALV_META-T_FCAT ASSIGNING <FIELD>.

      IF INSERT_VALUES IS NOT INITIAL.
        INSERT_VALUES = INSERT_VALUES && ','.
      ENDIF.

      ASSIGN COMPONENT <FIELD>-FIELDNAME OF STRUCTURE <WA> TO <VALUE>.
        IF <VALUE> IS ASSIGNED.
          IF <FIELD>-DATATYPE = 'DATS'.
            IF <VALUE> IS INITIAL.
              INSERT_VALUES = INSERT_VALUES && |''|.
            ELSE.
              DATUM = <VALUE>.
              DATA(DATE_STR) = |{ DATUM DATE = ISO }|.
              INSERT_VALUES = INSERT_VALUES && |'{ DATE_STR }'|.
            ENDIF.
          ELSEIF <FIELD>-DATATYPE = 'TIMS'.
            IF <VALUE> IS INITIAL.
              INSERT_VALUES = INSERT_VALUES && |''|.
            ELSE.
              UZEIT = <VALUE>.
              DATA(TIME_STR) = |{ UZEIT TIME = ISO }|.
              INSERT_VALUES = INSERT_VALUES && |'{ TIME_STR }'|.
            ENDIF.
          ELSE.
            INSERT_VALUES = INSERT_VALUES && |'{ <VALUE> }'|.
          ENDIF.
        ENDIF.

    ENDLOOP.

    DATA(INSERT) = |INSERT INTO { TABLE } VALUES ({ INSERT_VALUES })|.
    APPEND INSERT TO IT_INSERT.
    CLEAR: INSERT, INSERT_VALUES.
  ENDLOOP.

  IF IT_INSERT IS NOT INITIAL.
    DATA(DBCONN) = CL_SQL_CONNECTION=>GET_CONNECTION( 'SQL' ).
    DATA(INSERT_STATEMENT) = DBCONN->CREATE_STATEMENT( ).
    LOOP AT IT_INSERT INTO DATA(ROW).
      INSERT_STATEMENT->EXECUTE_UPDATE( ROW ).
    ENDLOOP.
  ENDIF.

  DBCONN->COMMIT( ).
  DBCONN->CLOSE( ).

  IF SY-SUBRC = 0.
    MESSAGE 'SQL operation successfull!' TYPE 'I' DISPLAY LIKE 'S'.
  ENDIF.

  CATCH CX_ROOT INTO DATA(CX_ERROR).
    DATA(ERROR) = CX_ERROR->GET_LONGTEXT( ).
    IF ERROR IS INITIAL.
      ERROR = CX_ERROR->GET_TEXT( ).
    ENDIF.
    MESSAGE ERROR TYPE 'I'.

ENDTRY.

esto concluye el paso final y esta publicación de blog

Este código también se puede usar para informes estándar y CDS, sin ningún problema

me gustaría mencionar que ESTE BLOG lo que me ayudó, mucho, a escribir mi código

Me encantaría tener sus comentarios




Introducción a SAP Data Migration Cockpit: PARTE 1
Previo
Resumen de diferentes tipos de ASDO en SAP BW, BW/4HANA y funcionalidades
Siguiente

Madrid

Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010

México

Paseo de la Reforma 26
Colonia Juárez,  Cuauhtémoc
Ciudad de México 06600

Costa Rica

Real Cariari
Autopista General Cañas, 
San José, SJ 40104

Perú

Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073

Twitter Linkedin Instagram
Copyright 2022 | All Right Reserved.

x