lunes, 3 de enero de 2011

Programas con DB2 III: COUNT, MAX y FOR UPDATE.

Para terminar con la saga, vamos a ver estos tres últimos casos.

SELECT COUNT:
Esta sentencia nos recuperará la cantidad de registros que cumplen una condición, es decir, lo que devuelve es un número.

EXEC SQL
   SELECT COUNT(*)
     INTO :NUMERO-REGISTROS :IND-NULL
     FROM TABLA1
    WHERE CAMPO1 = 'XX'
END-EXEC

La variable IND-NULL la definiremos como S9(4) COMP y la utilizaremos para controlar el retorno, en caso de que no encuentre ningún registro que cumpla la condición.

Controlando el SQLCODE:
EVALUATE TRUE
   WHEN SQLCODE EQUAL ZEROES
      IF IND-NULL EQUAL -1
         MOVE ZEROES TO NUMERO-REGISTROS
      END-IF
   WHEN OTHER
      DISPLAY 'ERROR HACIENDO EL SELECT COUNT. SQLCODE: 'SQLCODE
END-EVALUATE

El indicador de nulos para el caso de no encontrar ningún registro valdrá -1. Si no controlásemos el indicador de nulos, la SELECT nos devolvería un SQLCODE -305.


SELECT MAX:
Esta sentencia nos recuperará el valor máximo de un campo para una determinada condición.

EXEC SQL
   SELECT MAX(CAMPO2)
     INTO :TABLA1-CAMPO2 :IND-NULL
     FROM TABLA1
    WHERE CAMPO1 = 01
END-EXEC

El control del retorno se hará del mismo modo que para el SELECT COUNT:
EVALUATE TRUE
   WHEN SQLCODE EQUAL ZEROES
      IF IND-NULL EQUAL -1
         MOVE ZEROES TO TABLA1-CAMPO2
      END-IF
   WHEN OTHER
      DISPLAY 'ERROR HACIENDO EL SELECT COUNT. SQLCODE: 'SQLCODE
END-EVALUATE


FOR UPDATE:
Esta sentencia se utiliza para actualizar el registro en el que nos hemos posicionado con un FETCH.

EXEC SQL
   DECLARE CUR-TABLA1 CURSOR FOR
    SELECT
          CAMPO1,
          CAMPO2,
          CAMPO3,
          CAMPO4
      FROM TABLA1
     WHERE CAMPO1 = :TABLA1-CAMPO1
     FOR UPDATE OF
          CAMPO2,
          CAMPO3,
          CAMPO4
END-EXEC

En el programa haríamos un update por cada FETCH del siguiente modo:
EXEC SQL
   UPDATE TABLA1
     SET CAMPO2 = :UPD-CAMPO2,
         CAMPO3 = :UPD-CAMPO3,
         CAMPO4 = :UPD-CAMPO4
    WHERE CURRENT OF CUR-TABLA1
END-EXEC

De este modo no tendríamos que indicarle la clave del registro a actualizar, pues actualizaría el registro abierto por el FETCH.

8 comentarios:

José Antonio Romero dijo...

Una forma muy interesante, poco utilizada y menos costosa de hacer un SELECT MAX(campo) es:

SELECT campo
WHERE ...
ORDER BY campo DESC
FETCH FIRST 1 ROW ONLY

Con esto conseguimos que el DB/2 nos devuelva una única fila que además al estar ordenada de forma descendente por el campo buscado nos dará el valor deseado

Alvarito dijo...

Muchas gracias por la aportación José Antonio. Esperamos que más gente se anime a compartir su conocimiento.

LGS dijo...

Incluiría también el SELECT MIN.

Si en la select indicada en la entrada sustituimos MAX por MIN lo que recuperamos es el valor mínimo de un campo para una determinada condición.

Otra manera de hacer lo mismo sería utilizando la select indicada por José Antonio Romero modificando el ORDER BY (siendo ASC en lugar de DESC).

Guillermo F dijo...

pero para hacerla tuve que declarar un cursor porque en COBOL no me permite el ORDER BY en un SELECT

Unknown dijo...

Una consulta, que valor toma la variable "NUMERO-REGISTROS" cuando el select devuelve un NOT FOUND, en los siguientes casos:

1.- Sin variable IND-NULL
EXEC SQL
SELECT COUNT(*)
INTO :NUMERO-REGISTROS
FROM TABLA1
WHERE CAMPO1 = 'XX'
END-EXEC


2.- Con variable IND-NULL
EXEC SQL
SELECT COUNT(*)
INTO :NUMERO-REGISTROS :IND-NULL
FROM TABLA1
WHERE CAMPO1 = 'XX'
END-EXEC

gracias

Tallian dijo...

Buenas!
En el caso de no encontrar registros que cumplan la condición, sin el indicador IND-NULL no obtendrás un not found (+100) sino un -305 como se indica.
En ambos casos la variable NUMERO-REGISTROS toma valor NULL.

Unknown dijo...

Hola requiero un cursos que pueda recuperar "n" registros, se puede usar el FETCH FIRST ROWS ONLY en el cursor ?

Tallian dijo...

Hola. Para recuperar n registros en cada fetch puedes usar el cursor ROWSET. Si lo que quieres es limitar el número de registros devueltos por el cursor puedes indicarlo con el FETCH FIRST n ROWS ONLY.