Introducción
Aplicación de técnicas y conceptos básicos
Trabajar con clases locales
Lectura de datos de la base de datos
Trabajar con objetos de datos estructurados
Trabajar con tablas internas complejas
Implementación de actualizaciones de base de datos mediante business objects
Descripción del modelo de programación de aplicaciones ABAP RESTful

Implementación de sentencias SELECT básicas

Objectives

After completing this lesson, you will be able to:
  • Describa las funciones básicas de ABAP SQL.
  • Leer valores individuales de la base de datos.

Sintaxis ABAP SQL básica

Lenguaje de consulta estructurado (SQL)

Todos los sistemas de bases de datos relacionales utilizan una variante de Structured Query Language (SQL) para permitirle trabajar con ellos. SQL estándar consta de tres componentes principales:

Idioma de tratamiento de datos (DML)
DML se compone de las sentencias que necesita para trabajar con información en tablas de base de datos. Se trata de INSERT, para añadir nuevos registros, SELECT, para leer datos, UPDATE, para modificar registros existentes y DELETE, para borrar contenidos de tabla. Estas sentencias se reflejan en ABAP en forma de ABAP SQL.
Lenguaje de definición de datos (DDL)
Lenguaje de definición de datos le proporciona comandos que le permiten crear y eliminar tablas de bases de datos y otros artefactos de bases de datos como esquemas, índices de tablas y vistas. En un sistema SAP, estas tareas se realizan utilizando editores dedicados de ADT, no con programas ABAP. Un ejemplo es el editor de definiciones de tabla de base de datos que vimos anteriormente.
Lenguaje de control de datos (DCL)
El lenguaje de control de datos se utiliza en SQL para restringir el acceso a los datos de la base de datos para un usuario en particular. No se utiliza en su formato clásico en ABAP, ya que los usuarios en el nivel de base de datos no se corresponden con los usuarios finales. En consecuencia, ABAP tiene su propio concepto de autorización.

Arquitectura ABAP SQL

En el pasado, los sistemas SAP debían permitir un rango de plataformas de base de datos, y cada plataforma presentaba una implementación un poco diferente de la versión estándar de SQL. Esto significaba que cada plataforma necesitaba comandos ligeramente diferentes para lograr una tarea concreta. Para evitar que el código ABAP sea específico de la base de datos, SAP inventó ABAP SQL o Open SQL como se llamaba originalmente.

Nota

El cambio de nombre de Open SQL y ABAP SQL también ilustra que a partir de la versión 7.53 ABAP solo admite SAP HANA como DBMS.

ABAP SQL es un conjunto abstracto de comandos SQL implementados a nivel ABAP e integrados en el lenguaje ABAP. En tiempo de ejecución, ABAP SQL se convierte en una variante de SQL que la base de datos entiende. Esta variante se denomina Native SQL para distinguirla de ABAP SQL, la variante SQL que está integrada en ABAP. La traducción de ABAP SQL a Native SQL tiene lugar en la interfaz de base de datos, un componente del sistema ABAP que consta de una parte general y una biblioteca específica de base de datos.

Aunque las versiones ABAP más recientes solo admiten SAP HANA como DBMS, SAP aún ha conservado el concepto de ABAP SQL y la interfaz de base de datos. Esto se debe a los siguientes motivos:

Compatibilidad con la arquitectura
ABAP SQL y la interfaz de base de datos son una parte integral de la arquitectura del sistema.
Compatibilidad de código
La codificación ABAP SQL de productos SAP anteriores (incluido el desarrollo específico del cliente) debería ejecutarse sin efectos secundarios en los entornos ABAP modernos y solo en SAP HANA.
Tareas de la interfaz de base de datos
La interfaz de base de datos no solo traduce sentencias; también es responsable de tareas específicas de ABAP como, por ejemplo, el tratamiento automático de mandantes.

Lectura de registro individual de la base de datos

La sentencia SELECT en ABAP

Para leer datos de la base de datos, se utiliza la sentencia SELECT.

Al escribir una sentencia SELECT en ABAP SQL, la verificación de sintaxis compara lo que ha escrito con la definición de las tablas y vistas. Si intenta hacer referencia a tablas, vistas o campos que no existen, se produce un error de sintaxis.

La sintaxis básica de la sentencia SELECT contiene varias secciones, llamadas cláusulas, y siempre sigue el patrón de la figura, La sentencia SELECT en ABAP. Las cláusulas más importantes de una sentencia SELECT son las siguientes:

FROM
En la cláusula FROM de la sentencia SELECT, especifique el origen de datos del que desea leer. Puede ser una tabla de base de datos o una vista. Las técnicas SQL especiales le permiten combinar datos de varias fuentes en la misma sentencia SELECT.
CAMPOS
En la cláusula FIELDS de la sentencia SELECT, debe enumerar las columnas de la tabla de base de datos que desea leer. Las columnas de la lista deben estar separadas por comas. Si desea leer toda la línea de tabla, puede especificar FIELDS* en lugar de una lista de columnas. Sin embargo, tenga en cuenta que esto puede provocar que la base de datos trabaje mucho más que simplemente leer las columnas que necesita.
WHERE

En la cláusula WHERE, puede especificar una condición que describa qué filas de la tabla se leerán. Por ejemplo, la condición WHERE carrier_id = 'LH' significa que solo se leerán las filas (en las que la columna CARRIER_D contiene el valor LH).

La cláusula WHERE puede contener varias condiciones relacionadas con los operadores AND y OR. Por ejemplo, WHERE carrier_id = 'LH' y connection_id = '0400' devolvería los datos de la conexión de vuelo LH 0400. También puede negar las condiciones mediante NOT. La cláusula WHERE es la única cláusula que es opcional. Sin embargo, tenga en cuenta que sin una cláusula WHERE lee todos los datos de la tabla o si la tabla tiene un campo de mandante, todos los datos que pertenecen al mandante de inicio de sesión del usuario. Las SELECTs sin una cláusula WHERE pueden causar graves problemas de rendimiento y deben evitarse.

INTO
La cláusula INTO especifica la variable o variables del programa ABAP en las que se deben colocar los datos. Normalmente se trata de una estructura o una tabla interna y, idealmente, debería tener la misma secuencia de componentes que la lista de columnas en la cláusula FIELDS.

Nota

Verá otras formas de sintaxis SQL en ABAP. Estas son anteriores y se han conservado para garantizar la compatibilidad. Debería habituarse a utilizar la sintaxis moderna, porque ofrece muchas más funciones y características que la sintaxis anterior.

La figura, Ejemplo 1: Lectura de campo individual de registro individual, ilustra una sentencia SELECT que lee un valor individual de la base de datos. La cláusula FROM nos indica que la sentencia lee de la tabla de base de datos /DMO/CONNECTION. La opción SINGLE, después de la palabra clave SELECT, indica que solo se lee una fila (un registro individual). Esta fila se identifica en la cláusula WHERE proporcionando valores de filtro clave para los campos clave carrier_id y connection_id. Tenga en cuenta que la interfaz de base de datos añadirá un filtro en el mandante de campo clave restante.

La cláusula FIELDS enumera solo una columna de la tabla: columna AIRPORT_FROM_ID.

La cláusula INTO debe coincidir con el resto de la sentencia. En nuestro ejemplo, esto especifica la variable airport_from_id como el objeto de destino, un objeto de datos escalar de tipo idéntico como campo de tabla, airport_from_id.

Nota

El signo arroba (@) identifica airport_from_id como el nombre de un objeto de datos ABAP. Es obligatorio para todas las variables y constantes que utiliza en una sentencia ABAP SQL. Es necesario para evitar ambigüedades si, por ejemplo, un objeto de datos y un campo de tabla tienen el mismo nombre.

La figura, Ejemplo 2: Lectura de varios campos de registro individual, ilustra una sentencia SELECT que lee dos valores del mismo registro de la base de datos.

Esta vez, la cláusula FIELDS enumera dos columnas de la tabla; columna AIRPORT_FROM_ID y columna AIRPORT_TO_ID.

Para que coincida con esto, la cláusula INTO especifica las variables airport_from_id y airport_to_id como objetos de destino. Están separados por una coma y rodeados por un par de corchetes para dejar claro que juntos forman el destino de la sentencia SELECT.

Cuando implementa una sentencia SELECT, siempre debe tener en cuenta que no podría haber ningún resultado, ya sea porque la tabla de base de datos no contiene ningún dato o porque no contiene ninguna fila que cumpla las condiciones de la cláusula WHERE. En el ejemplo de la figura anterior, la tabla de base de datos no contiene una fila con carrier_id = 'XX' y connection_id = '1234'.

ABAP SQL utiliza el campo de sistema SY-SUBRC para indicar una ejecución correcta o incorrecta de una sentencia. El campo de sistema SY-SUBRC es de tipo entero. El valor inicial 0 siempre indica una ejecución correcta. Si, después de una sentencia SELECT, SY-SUBRC contiene el valor 4, esto indica que la base de datos ha devuelto un resultado vacío.

Si la base de datos devuelve un resultado vacío, ABAP SQL NO toca la variable de destino después de INTO.

En particular, la variable de destino no se inicializa en caso de error.

Se recomienda evaluar el contenido del campo de sistema sy-subrc inmediatamente después de cada sentencia SELECT.

Pruébelo: SELECCIONE Ejemplos

  1. Como en el primer ejercicio de este curso, cree una nueva clase global que implemente la interfaz IF_OO_ADT_CLASSRUN.
  2. Copie el siguiente fragmento de código en la parte de implementación del 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. Pulse CTRL + F3 para activar la clase y F9 para ejecutarla como una aplicación de consola.
  4. Analice la salida de la consola. Depurar el programa, jugar con el código fuente para familiarizarse con los conceptos.

Leer datos de una tabla de base de datos

En este ejercicio, amplíe su clase local con atributos para el aeropuerto de salida y el aeropuerto de destino, y lea los valores para estos atributos de una tabla de base de datos.

Modelo:

  • /LRN/CL_S4D400_CLS_CONSTRUCTOR (clase global)

Solución:

  • /LRN/CL_S4D400_DBS_SELECT (clase global)

Tarea 1: Copiar plantilla

Copie la clase de modelo. Como alternativa, copie la solución del ejercicio anterior.

Pasos

  1. Copie la clase /LRN/CL_S4D400_CLS_CONSTRUCTOR en una clase de su propio paquete (nombre sugerido: ZCL_##_SELECT, donde ## representa su número de grupo).

    1. Abra el código fuente de la clase global /LRN/CL_S4D400_CLS_CONSTRUCTOR.

    2. Vincule la vista Explorador de proyectos con el editor.

    3. En la vista Explorador de proyectos, haga clic con el botón derecho en la clase /LRN/CL_S4D400_CLS_CONSTRUCTOR para abrir el menú contextual.

    4. En el menú contextual, seleccione Duplicar ....

    5. Introduzca el nombre del paquete en el campo Paquete. En el campo Nombre, introduzca el nombre ZCL_##_SELECT, donde ## representa su número de grupo.

    6. Ajuste la descripción y seleccione Siguiente.

    7. Confirme la orden de transporte y seleccione Finalizar.

Tarea 2: Declarar atributos adicionales

Amplíe la clase local lcl_connection con los atributos de instancia privada airport_from_id y airport_to_id. Añada algunas salidas para los nuevos atributos a la implementación del método get_output.

Nota

Los nuevos atributos aún no se han rellenado. Para rellenarlos, añadiremos una sentencia SELECT al constructor en una de las siguientes tareas de este ejercicio.

Pasos

  1. Cambie a la clase local lcl_connection.

    1. En la clase global, seleccione Tipos locales.

  2. Añada los siguientes atributos privados a la definición de clase:

    Atributos

    Nombre de atributoAlcanceTipo de datos
    airport_from_idinstancia/DMO/AIRPORT_FROM_ID
    aeropuerto_to_idinstancia/DMO/AIRPORT_TO_ID
    1. Ajuste el código de la siguiente manera:

      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. Amplíe la implementación del método get_output. Añada más plantillas de cadena al parámetro de retorno r_output. Incruste los nuevos atributos como expresiones en los modelos de cadena.

    1. Navegue a la implementación del método get_output.

    2. Ajuste el código de la siguiente manera:

      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. Active la clase. Ejecútelo y analice la salida de la consola.

    1. Pulse Ctrl + F3 para activar la clase.

    2. Pulse F9 para ejecutar la clase.

Tarea 3: Analizar la tabla de base de datos

Analice la definición de la tabla de base de datos /DMO/CONNECTION.

Pasos

  1. Abra el objeto de desarrollo que contiene la definición de la tabla de base de datos /DMO/CONNECTION.

    1. En la barra de herramientas de eclipse, seleccione Abrir objeto de desarrollo ABAP o pulse Ctrl + Mayús + A.

    2. En el campo de entrada, introduzca /dmo/con como string de búsqueda.

    3. En la lista de posiciones coincidentes, haga clic en /DMO/CONNECTION (Tabla de base de datos) y seleccione OK.

  2. Abra la información de elemento (F2) para la tabla de base de datos /DMO/CONNECTION.

    1. Haga clic en /dmo/connection después de la palabra clave define table y pulse F2 para mostrar la información del elemento.

Tarea 4: Leer datos de la base de datos

En el constructor de método de la clase local lcl_connection, implemente una sentencia SELECT que lea valores para los nuevos atributos de la tabla de base de datos /DMO/CONNECTION.

Pasos

  1. Vuelva a la clase local lcl_connection en su clase global.

    1. En la vista de editor de Eclipse, abra la pestaña ZCL_##_SELECT.

    2. En la clase global, seleccione Tipos locales.

  2. Navegue a la implementación del constructor de métodos.

    1. Busque la línea de código METHOD constructor..

  3. Después de la sentencia ENDIF., añada una sentencia SELECT que lea un registro individual de la tabla de base de datos /DMO/CONNECTION.

    1. Ajuste el código de la siguiente manera:

      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 la cláusula FIELDS. Lea los campos de tabla airport_from_id y airport_to_id.

    Consejo

    Utilice la finalización automática (Ctrl + Espacio) para introducir los nombres de campo.
    1. Después de FROM /DMO/CONNECTION, introduzca FIELDS.

    2. Después de un espacio en blanco, pulse Ctrl + Espacio y seleccione airport_from_id.

    3. Después de una coma y en blanco, pulse Ctrl + Espacio de nuevo y seleccione airport_to_id.

    4. La cláusula FIELDS completa debería tener el siguiente aspecto:

      Code Snippet
      123
      FIELDS airport_from_id, airport_to_id
  5. Implemente la condición WHERE. Restrinja todos los campos clave de la tabla de base de datos (excepto el campo de cliente) con los valores de los parámetros de importación i_carrier_id e i_connection_id. No olvide escapar de los parámetros con el prefijo @.

    Consejo

    Utilice la finalización automática (Ctrl + Espacio) para introducir los nombres de los elementos y los nombres de los parámetros.
    1. Añada el siguiente código después de la cláusula FIELDS:

      Code Snippet
      1234
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id
  6. Implemente la cláusula INTO. Almacene el resultado SELECT en los atributos airport_from_id y airport_to_id. No olvide escapar de los atributos con el prefijo @.

    Consejo

    Utilice la finalización automática (Ctrl + Espacio) para introducir los nombres de atributo.
    1. Ajuste el código de la siguiente manera:

      Code Snippet
      123456
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
    2. La sentencia SELECT completa debería tener el siguiente 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 el tratamiento de errores después de la sentencia SELECT. Verifique el contenido del campo de sistema sy-subrc. Si no es igual a cero, emita la excepción CX_ABAP_INVALID_VALUE.

    1. Añada el siguiente código después de la sentencia SELECT:

      Code Snippet
      12345
      IF sy-subrc <> 0. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF.
  8. Active la clase. Ejecútelo y analice la salida de la consola. Verifique que la salida de los nuevos atributos muestre datos.

    1. Pulse Ctrl + F3 para activar la clase.

    2. Pulse F9 para ejecutar la clase.