Soporte de SQL

Como se muestra en la tabla siguiente, el código generado por EGL puede acceder a una base de datos relacional en cualquiera de los sistemas destino.

Sistema destino Soporte para el acceso a bases de datos relacionales
AIX, HP-UX, iSeries, Linux, Solaris, UNIX System Services, Windows 2000/NT/XP JDBC proporciona acceso a DB2 UDB, Oracle, Informix o Microsoft SQL Server

Mientras trabaja en un programa, puede codificar las sentencias SQL de la misma manera que lo haría para codificar programas en la mayoría de los demás lenguajes. Para facilitarle el trabajo, EGL proporciona plantillas de sentencias SQL para que las rellene.

Como alternativa, puede utilizar un registro SQL como objeto de E/S cuando codifique una sentencia EGL. Esta utilización del registro significa que accede a una base de datos personalizando una sentencia SQL que se le ha proporcionado o bien dependiendo de un valor por omisión que elimina la necesidad de codificar SQL.

En cualquiera de los dos casos, tenga en cuenta los siguientes aspectos del soporte de EGL:

SQL y sentencias EGL

La tabla siguiente muestra las palabras clave EGL que puede utilizar para acceder a una base de datos relacional. Esta tabla también incluye una descripción de las sentencias SQL correspondientes a cada palabra clave. Cuando se codifica una sentencia EGL add, por ejemplo, se genera una sentencia SQL INSERT.

En muchas aplicaciones empresariales, se utiliza la sentencia open de EGL y diversas clases de sentencias get by position. El código ayuda a declarar, abrir y procesar un cursor, que es una entidad de tiempo de ejecución que actúa de la forma siguiente:
  • Devuelve un conjunto de resultados, con una lista de las filas que cumplen los criterios de búsqueda
  • Señala a una fila específica del conjunto de resultados

Puede utilizar la sentencia EGL open para llamar a un procedimiento almacenado. Este procedimiento se compone de lógica que está escrita fuera de EGL, se almacena en el sistema de gestión de bases de datos y también devuelve un conjunto de resultados. (Además, puede utilizar la sentencia EGL execute para llamar a un procedimiento almacenado).

En secciones siguientes se proporcionan detalles sobre cómo procesar un conjunto de resultados.

Si tiene la intención de codificar explícitamente sentencias SQL, utilice la sentencia EGL execute y posiblemente la sentencia EGL prepare.

Palabra clave/finalidad Descripción de las sentencias SQL ¿Se puede modificar la SQL?
add

Coloca una fila en una base de datos; o bien (si se utiliza una matriz dinámica de registros SQL), coloca un conjunto de filas en función del contenido de los elementos sucesivos de la matriz.

INSERT row (ya que aparece repetidamente, si especifica una matriz dinámica).
close

Libera las filas no procesadas.

CLOSE cursor. No
delete

Suprime una fila de una base de datos.

DELETE row. La fila se ha seleccionado de una de las dos maneras siguientes:
  • Al invocar una sentencia get con la opción forUpdate (según sea apropiado cuando desee seleccionar la primera de varias filas que tienen el mismo valor de clave)
  • Al invocar una sentencia open con la opción forUpdate y luego una sentencia get next (según sea apropiado cuando desee seleccionar un conjunto de filas y procesar los datos recuperados en un bucle)
No
forEach

Marca el inicio de un conjunto de sentencias que se ejecutan en un bucle. La primera iteración se produce solamente si un conjunto de resultados especificado está disponible y continúa (en la mayoría de los casos) hasta que se ha procesado la última fila de ese conjunto de resultados.

EGL convierte una sentencia forEach en una sentencia FETCH de SQL que se ejecuta en un bucle. No
freeSQL

Libera los recursos asociados a una sentencia SQL preparada dinámicamente, cerrando cualquier cursor abierto asociado con esa sentencia SQL.

  No
get (también llamada get by key value)

Lee una única fila de una base de datos; o bien (si utiliza una matriz dinámica de registros SQL), lee filas sucesivas de elementos sucesivos de la matriz.

SELECT row, pero sólo si establece la opción singleRow. En caso contrario, se aplican las siguientes normas:
  • EGL convierte una sentencia get en:
    • DECLARE cursor con SELECT o (si establece la opción forUpdate) con SELECT FOR UPDATE.
    • OPEN cursor.
    • FETCH row.
  • Si no ha especificado la opción forUpdate, EGL también cierra el cursor.
  • Las opciones singleRow y forUpdate no están soportadas con matrices dinámicas; en este caso, el entorno de ejecución EGL declara y abre un cursor, extrae una serie de filas y cierra el cursor.
get absolute

Lee una fila especificada numéricamente en un conjunto de resultados seleccionado por una sentencia open.

EGL convierte una sentencia get absolute en una sentencia FETCH de SQL. No
get current

Lee la flecha en la que el cursor ya está posicionado en un conjunto de resultados seleccionado por una sentencia open.

EGL convierte una sentencia get current en una sentencia FETCH de SQL. No
get first

Lee la primera fila de un conjunto de resultados seleccionado por una sentencia open.

EGL convierte una sentencia get first en una sentencia FETCH de SQL. No
get last

Lee la última fila de un conjunto de resultados seleccionado por una sentencia open.

EGL convierte una sentencia get last en una sentencia FETCH de SQL. No
get next

Lee la fila siguiente de un conjunto de resultados seleccionado por una sentencia open.

EGL convierte una sentencia get next en una sentencia SQL FETCH. No
get previous

Lee la fila anterior de un conjunto de resultados seleccionado por una sentencia open.

EGL convierte una sentencia get previous en una sentencia FETCH de SQL. No
get relative

Lee una fila especificada numéricamente en un conjunto de resultados seleccionado por una sentencia open. La fila se identifica en relación con la posición del cursor en el conjunto de resultados.

EGL convierte una sentencia get relative en una sentencia FETCH de SQL. No
execute

Permite ejecutar una sentencia de definición de datos SQL (de tipo CREATE TABLE, por ejemplo); o una sentencia de manipulación de datos (de tipo INSERT o UPDATE, por ejemplo); o una sentencia SQL preparada que no empieza con una cláusula SELECT.

La sentencia SQL que se escribe está disponible en el sistema de gestión de bases de datos.
El uso principal de execute es codificar una única sentencia SQL que se formatea completamente durante la generación, como en el siguiente ejemplo:
try
  execute
  #sql{    // sin ningún espacio después de "#sql"
    delete
    from EMPLOYEE
    where department = 
      :myRecord.department  
  };
onException
  myErrorHandler(10);
end

Una sentencia SQL completamente formateada puede incluir variables del lenguaje principal en la cláusula WHERE.

open

Selecciona un conjunto de filas a partir de una base de datos relacional para recuperarlas posteriormente con las sentencias get next.

EGL convierte una sentencia open en una sentencia CALL (para acceder a un procedimiento almacenado) o en las siguientes sentencias:
  • DECLARE cursor con SELECT o con SELECT FOR UPDATE.
  • OPEN cursor.
prepare

Especifica una sentencia SQL PREPARE, que opcionalmente incluye detalles que sólo se conocen durante la ejecución; ejecute la sentencia SQL preparada ejecutando una sentencia EGL execute o (si la sentencia SQL empieza con SELECT) ejecutando una sentencia EGL open o get.

EGL convierte una sentencia prepare en una sentencia SQL PREPARE, que siempre se construye durante la ejecución. En el siguiente ejemplo de una sentencia EGL prepare, cada marcador de parámetro (?) se resuelve mediante la cláusula USING en la sentencia execute subsiguiente:
myString = 
  "insert into myTable " +
  "(empnum, empname) " +
    "value ?, ?";

try
  prepare myStatement 
    from myString;
onException
  // salir del programa
  myErrorHandler(12); 
end

try
  execute myStatement 
  using :myRecord.empnum,
        :myRecord.empname;
onException
  myErrorHandler(15);
end
replace

Vuelve a poner una fila cambiada en una base de datos.

UPDATE row. La fila se ha seleccionado de una de las dos maneras siguientes:
  • Al invocar una sentencia get con la opción forUpdate (según sea apropiado cuando desee seleccionar la primera de varias filas que tienen el mismo valor de clave); o bien
  • Al invocar una sentencia open con la opción forUpdate y luego una sentencia get next (según sea apropiado cuando desee seleccionar un conjunto de filas y procesar los datos recuperados en un bucle).
Nota: En ningún caso se pueden actualizar varias tablas de base de datos codificando una única sentencia EGL.

Proceso del conjunto de resultados

Una forma habitual de actualizar una serie de filas es la siguiente:
  1. Declare y abra un cursor ejecutando una sentencia EGL open con la opción forUpdate; esta opción hace que las filas seleccionadas se bloqueen para una posterior actualización o supresión
  2. Obtenga una fila ejecutando una sentencia EGL get next
  3. Realice lo siguiente en un bucle:
    1. Cambie los datos de las variables del lenguaje principal en las que ha recuperado los datos
    2. Actualice la fila ejecutando una sentencia EGL replace
    3. Obtenga otra fila ejecutando la sentencia EGL get next
  4. Comprometa los cambios ejecutando la función EGL commit.

Las sentencias que abren el cursor y que actúan sobre las filas de dicho cursor están relacionadas entre sí mediante un identificador de conjunto de resultados, que debe ser exclusivo entre todos los identificadores de conjunto de resultados, variables de programa y parámetros de programa dentro del programa. Especifique dicho identificador en la sentencia open que abre el cursor, y haga referencia al mismo identificador en las sentencias get next, delete y replace que afectan a una fila individual, así como en la sentencia close que cierra el cursor. Para obtener información detallada, consulte la sección resultSetID.

El código siguiente muestra cómo actualizar una serie de filas cuando codifique SQL usted mismo:
  VGVar.handleHardIOErrors  = 1;

  try
    open selectEmp forUpdate with
    #sql{    // sin ningún espacio después de "#sql"
      select empname
      from EMPLOYEE
      where empnum >= :myRecord.empnum
      for update of empname
    };
      
  onException
    myErrorHandler(8);  // sale del programa
  end

  try
    get next from selectEmp into :myRecord.empname;
  onException
    if (sysVar.sqlcode != 100)
      myErrorHandler(8);  // salir del programa
    end
  end

  while (sysVar.sqlcode != 100) 
    myRecord.empname = myRecord.empname + " " + "III";

    try
      execute
      #sql{
        update EMPLOYEE
        set empname = :empname
        where current of selectEmp
      };
    onException
      myErrorHandler(10);   // sale del programa
    end

    try
      get next from selectEmp into :myRecord.empname;
    onException
      if (sysVar.sqlcode != 100)
        myErrorHandler(8);  // sale del programa
      end 
    end
  end  // end while; el cursor se cierra automáticamente
       // cuando se lee la última fila del conjunto de resultados

  sysLib.commit;

Si desea evitar parte de la complejidad del ejemplo anterior, considere la posibilidad de utilizar registros SQL. Estos registros permiten perfeccionar el código y utilizar valores de error de E/S que no varían en los diferentes sistemas de gestión de bases de datos. El siguiente ejemplo es equivalente al anterior pero utiliza un registro SQL llamado emp:

  VGVar.handleHardIOErrors  = 1;

  try
    open selectEmp forUpdate for emp;
  onException
    myErrorHandler(8);  // sale del programa
  end

  try
    get next emp;
  onException
    if (sysVar.sqlcode not noRecordFound)
      myErrorHandler(8);  // salir del programa
    end 
  end

  while (sysVar.sqlcode not noRecordFound) 
    myRecord.empname = myRecord.empname + " " + "III";

    try 
      replace emp;
    onException
      myErrorHandler(10);   // sale del programa
    end

    try
      get next emp;
    on exception
      if (sysVar.sqlcode not noRecordFound)
        myErrorHandler(8);  // sale del programa
      end
    end
  end  // end while; el cursor se cierra automáticamente
       // cuando se lee la última fila del conjunto de resultados

  sysLib.commit;

En las secciones siguientes se describen los registros SQL.

Registros SQL y sus usos

Un registro SQL es una variable que se basa en un componente de registro SQL. Este tipo de registro permite interactuar con una base de datos relacional como si se estuviera accediendo a un archivo. Si, por ejemplo, la variable EMP se basa en un componente de registro SQL que hace referencia a la tabla de base de datos EMPLOYEE, se puede utilizar EMP en una sentencia EGL add:
  add EMP;
En este caso, EGL inserta los datos de EMP en EMPLOYEE. El registro SQL también incluye información de estado de modo que después de ejecutarse la sentencia EGL, se puede probar el registro SQL para que realice tareas condicionalmente, de acuerdo con el valor de error de E/S que se ha obtenido del acceso a la base de datos:
  VGVar.handleHardIOErrors  = 1;

  try
    add EMP;
  onException
    if (EMP is unique)     // si una fila de la tabla 
                          // tenía la misma clave
      myErrorHandler(8);
    end
  end
Un registro SQL, como por ejemplo EMP, permite interactuar con una base de datos relacional del modo siguiente:
  • Declare un componente de registro SQL y el registro SQL relacionado
  • Defina un conjunto de sentencias EGL de modo que cada una de ellas utilice el registro SQL como un objeto de E/S
  • Acepte el comportamiento por omisión de las sentencias EGL o bien realice los cambios en SQL que sean apropiados para la lógica empresarial

Declarar un componente de registro SQL y el registro relacionado

Declare un componente de registro SQL y asocie cada uno de los elementos de registro con una columna de la tabla o vista relacional. Puede permitir que EGL realice esta asociación automáticamente utilizando la característica de recuperación del editor EGL, como se describe más adelante en la sección Acceso a base de datos durante la declaración.

Si el componente de registro SQL no es un componente de registro fijo, puede incluir campos primitivos así como otras variables. Probablemente incluirá las clases de variables siguientes:
  • Otros registros SQL. La presencia de cada uno representa una relación uno a uno entre las tablas padre e hijo.
  • Matrices de registros SQL. La presencia de cada uno representa una relación de uno a muchos entre las tablas padre e hijo.

Solo los campos de un tipo primitivo pueden representar una columna de base de datos.

si los números de nivel preceden a los campos, el componente de registro SQL es un componente de registro fijo. Se aplican las siguientes normas:
  • La estructura de cada componente de registro SQL debe ser plana (sin jerarquía).
  • Todos los campos deben ser campos primitivos, pero no de tipo BLOB, CLOB o STRING
  • Ninguno de los campos de registro puede ser una matriz de campo de estructura

Después de declarar un componente de registro SQL, declare un registro SQL que se base en dicho componente.

Definir las sentencias EGL relacionadas con SQL

Puede definir un conjunto de sentencias EGL de modo que cada una de ellas utilice el registro SQL como objeto de E/S de la sentencia. Para cada sentencia, EGL proporciona una sentencia SQL implícita, que no está en el fuente pero está implícita por la combinación del registro SQL y la sentencia EGL. Por ejemplo, en el caso de una sentencia EGL add, una sentencia SQL INSERT implícita coloca el valor de un determinado elemento de registro en la columna de tabla asociada. Si el registro SQL incluye un elemento de registro para el que no se ha asignado ninguna columna de tabla, EGL forma la sentencia SQL implícita suponiendo que el nombre del elemento de registro es idéntico al nombre de la columna.

Utilizar sentencias SELECT implícitas

Cuando se define una sentencia EGL que utiliza un registro SQL y que genera una sentencia SQL SELECT o una declaración de cursor, EGL proporciona una sentencia SQL SELECT implícita. (Esta sentencia se incorpora en la declaración de cursor, si existe). Por ejemplo, podría declarar una variable llamada EMP que estuviera basada en el siguiente componente de registro:
  Record Employee type sqlRecord
    { tableNames = [["EMPLOYEE"]],
      keyItems = ["empnum"] }
    empnum decimal(6,0);
    empname char(40);
  end
A continuación, podría codificar una sentencia get:
  get EMP;
La sentencia SQL SELECT implícita es la siguiente:
  SELECT empnum, empname
  FROM   EMPLOYEE
  WHERE  empnum = :empnum
EGL también coloca una cláusula INTO en la sentencia SELECT autónoma (si no hay ninguna declaración de cursor) o en la sentencia FETCH asociada al cursor. La cláusula INTO lista las variables del lenguaje principal que reciben valores de las columnas listadas en la primera cláusula de la sentencia SELECT:
  INTO :empnum, :empname
La sentencia SELECT implícita lee el valor de cada columna en la variable del lenguaje principal correspondiente; hace referencia a las tablas especificadas en el registro SQL; y tiene un criterio de búsqueda (una cláusula WHERE) que depende de una combinación de dos factores:
  • El valor que se ha especificado para la propiedad de registro defaultSelectCondition; y
  • Una relación (como por ejemplo una igualdad) entre dos conjuntos de valores:
    • Los nombres de las columnas que constituyen la clave de tabla
    • Los valores de las variables del lenguaje principal que constituyen la clave de registro
Se produce una situación especial si lee datos en una matriz dinámica de registros SQL, como ocurre con la sentencia get:
  • Un cursor está abierto, filas sucesivas de la base de datos se leen en elementos sucesivos de la matriz, el conjunto de resultados se libera y el cursor se cierra.
  • Si no se especifica una sentencia SQL, el criterio de búsqueda depende de la propiedad de registro defaultSelectCondition, pero también depende de una relación (concretamente, una relación de mayor o igual que) entre los siguientes conjuntos de valores:
    • Los nombres de columnas, como se especifica indirectamente al especificar elementos en la sentencia EGL
    • Los valores de dichos elementos

    Todas las variables del lenguaje principal especificadas en la propiedad defaultSelectCondition deben estar fuera del registro SQL que es la base de la matriz dinámica.

Para obtener información detallada sobre la sentencia SELECT implícita, que varía según la palabra clave, consulte las secciones get y open.

Utilizar registros SQL con cursores

Cuando utilice registros SQL, puede relacionar las sentencias de proceso de cursores utilizando el mismo registro SQL en varias sentencias EGL, de la misma manera que puede hacerlo utilizando un identificador de conjunto de resultados. Sin embargo, cualquier relación entre sentencias que se indique mediante un identificador de conjunto de resultados tiene preferencia sobre una relación indicada mediante el registro SQL; y en algunos casos debe especificar un resultSetID.

Además, sólo un cursor puede estar abierto para un determinado registro SQL. Si una sentencia EGL abre un cursor cuando otro cursor está abierto para el mismo registro SQL, el código generado cierra automáticamente el primer cursor.

Personalizar las sentencias SQL

Dada una sentencia EGL que utiliza un registro SQL como objeto de E/S, puede actuar de una de las dos maneras siguientes:
  • Puede aceptar la sentencia SQL implícita. En este caso, los cambios realizados en el componente de registro SQL afectan a las sentencias SQL utilizadas durante la ejecución. Si, por ejemplo, más adelante indica que debe utilizarse un elemento de registro distinto como clave del registro SQL, EGL cambiará la sentencia SELECT implícita utilizada en cualquier declaración de cursor que se base en dicho componente de registro SQL.
  • En su lugar, puede elegir hacer explícita la sentencia SQL. En este caso, los detalles de dicha sentencia SQL se aíslan del componente de registro SQL y los cambios subsiguientes que se realicen en el componente de registro SQL no tendrán ningún efecto sobre la sentencia SQL que se utilice durante la ejecución.

    Si se elimina una sentencia SQL explícita del fuente, la sentencia SQL implícita (si existe) vuelve a estar disponible durante la generación.

Ejemplo de utilización de un registro en un registro

Para permitir que un programa recupere datos para una serie de empleados en un departamento, puede crear dos componentes de registro y una función, de la forma siguientes:
	DataItem DeptNo { column = deptNo } end

 Record Dept type SQLRecord
   deptNo DeptNo;
   managerID CHAR(6);
   employees Employee[];
 end

 Record Employee type SQLRecord
   employeeID CHAR(6);
   empDeptNo DeptNo;
 end

 Function getDeptEmployees(dept Dept)
   get dept.employees usingKeys dept.deptNo;
 end

Probar y establecer NULL

La opción del descriptor de construcción itemsNullable controla la circunstancia en que EGL mantiene internamente un indicador nulo para una variable primitiva en el código. Si acepta el valor por omisión, EGL mantiene internamente un indicador nulo para cada variable que tenga estas características:
  • Está en un registro SQL
  • Se declara con la propiedad isNullable establecida en yes

No codifique variables del lenguaje principal para indicadores de nulos en las sentencias SQL, como podría hacer en algunos lenguajes. Para probar los nulos de una variable del lenguaje principal con posibilidad de nulos, utilice una sentencia EGL if. También puede probar la recuperación de un valor truncado, pero sólo cuando un indicador de nulos está disponible.

Puede anular una columna de tabla SQL de una de las dos maneras siguientes:
  • Utilice una sentencia EGL set para anular una variable del lenguaje principal con posibilidad de nulos y, a continuación, escriba el registro SQL relacionado en la base de datos; o bien
  • Utilice la sintaxis SQL apropiada, escribiendo una sentencia SQL desde cero o personalizando una sentencia SQL que está asociada a la sentencia EGL add o replace.

Para conocer más detalles sobre el proceso nulo, consulte las secciones isNullable y itemsNullable.

Acceso a base de datos durante la declaración

El acceso (durante la declaración) a una base de datos que tiene características similares a la base de datos a la que accederá el código durante la ejecución tiene las siguientes ventajas:
  • Si accede a una tabla o vista de base de datos que es equivalente a una tabla o vista asociada a un registro SQL, puede utilizar la característica de recuperación del editor de componentes EGL para crear o sobrescribir los elementos de registro. La característica de recuperación accede a la información almacenada en el sistema de gestión de bases de datos de modo que el número y las características de datos de los elementos creados refleja el número y las características de las columnas de tabla. Después de invocar la característica de recuperación, puede redenominar los elementos de registro, suprimir los elementos de registro y realizar otros cambios en el registro SQL.
  • El acceso a una base de datos estructurada apropiadamente durante la declaración ayuda a asegurar que las sentencias SQL serán válidas en relación con una base de datos equivalente durante la ejecución.

La característica de recuperación crea elementos de registro cada uno de los cuales tiene el mismo nombre (o casi el mismo nombre) que la columna de tabla relacionada.

No se puede recuperar una vista que está definida con la condición de DB2 WITH CHECK OPTIONS.

Para obtener más información sobre cómo utilizar la característica de recuperación, consulte el apartado Recuperar datos de tabla SQL. Para obtener información detallada sobre denominación, consulte la sección Establecer las preferencias de la recuperación SQL.

Para acceder a una base de datos durante la declaración, especifique información de conexión en una página de preferencias, como se describe en la sección Establecer las preferencias de las conexiones de base de datos SQL.

Comentarios
(C) Copyright IBM Corporation 2000, 2005. Reservados todos los derechos.