El comando EXECUTE STATEMENT puede ser muy útil para realizar muchas tareas porque nos permite armar la instrucción que necesitamos ejecutar de muchas maneras. El tema es: cuando la instrucción que queremos ejecutar requiere de variables ¿cómo la armamos?

Tenemos tres posibilidades:

  1. Concatenando los parámetros
  2. Usando parámetros con nombres
  3. Usando parámetros por posición

Ejemplo:

(Este es un ejemplo muy sencillo y hay mejores formas de resolverlo pero sirve para demostrar como usar EXECUTE STATEMENT con parámetros)

Queremos crear un stored procedure que nos muestre los productos cuyos precios de venta están dentro del rango especificado.

Esta es nuestra tabla de PRODUCTOS:

EXECUTE1

Captura 1. Si haces clic en la imagen la verás más grande

1. Concatenando los parámetros

CREATE PROCEDURE EXECUTE1(
   tnPrecio1 INTEGER,
   tnPrecio2 INTEGER)
RETURNS(
   ftcNombre VARCHAR(40),
   ftnPrecio INTEGER)
AS
   DECLARE VARIABLE lcComando VARCHAR(1000);
BEGIN

  lcComando = 'SELECT
                  PRD_NOMBRE,
                  PRD_PREVTA
               FROM
                  PRODUCTOS
               WHERE
                  PRD_PREVTA >= ' || tnPrecio1 || ' AND
                  PRD_PREVTA <= ' || tnPrecio2;

   FOR EXECUTE STATEMENT
      lcComando
   INTO
      :ftcNombre,
      :ftnPrecio
   DO BEGIN
      SUSPEND;
   END

END;

Como este es un stored procedure seleccionable para ejecutarlo debemos escribir algo como:

SELECT * FROM EXECUTE1(3000, 5000)

y este será el resultado que obtendremos:

EXECUTE2
Captura 2. Si haces clic en la imagen la verás más grande

2. Usando parámetros con nombres

CREATE PROCEDURE EXECUTE2(
   tnPrecio1 INTEGER,
   tnPrecio2 INTEGER)
RETURNS(
   ftcNombre VARCHAR(40),
   ftnPrecio INTEGER)
AS
   DECLARE VARIABLE lcComando VARCHAR(1000);
BEGIN

   lcComando = 'SELECT
                   PRD_NOMBRE,
                   PRD_PREVTA
                FROM
                   PRODUCTOS
                WHERE
                   PRD_PREVTA >= :lnPrecio1 AND
                   PRD_PREVTA <= :lnPrecio2';

   FOR EXECUTE STATEMENT
      (lcComando) (lnPrecio1 := tnPrecio1, lnPrecio2 := tnPrecio2)
   INTO
      :ftcNombre,
      :ftnPrecio
   DO BEGIN
      SUSPEND;
   END

END;

En este caso dentro de lcComando usamos dos variables locales llamadas lnPrecio1 y lnPrecio2. Pero esas variables no es necesario declararlas después del AS (puedes declararlas si quieres, pero no es necesario).

Como estamos usando parámetros con nombres, no importa el orden en el cual especificamos los parámetros. O sea que ambas de estas formas son equivalentes, podemos usar cualquiera de ellas:

FOR EXECUTE STATEMENT
   (lcComando) (lnPrecio1 := tnPrecio1, lnPrecio2 := tnPrecio2)

FOR EXECUTE STATEMENT
   (lcComando) (lnPrecio2 := tnPrecio2, lnPrecio1 := tnPrecio1)

Como puedes ver nuestros parámetros tienen nombres (en este ejemplo: lnPrecio1 y lnPrecio2)

3. Usando parámetros por posición

CREATE PROCEDURE EXECUTE3(
   tnPrecio1 INTEGER,
   tnPrecio2 INTEGER)
RETURNS(
   ftcNombre VARCHAR(40),
   ftnPrecio INTEGER)
AS
   DECLARE VARIABLE lcComando VARCHAR(1000);
BEGIN

   lcComando = 'SELECT
                   PRD_NOMBRE,
                   PRD_PREVTA
                FROM
                   PRODUCTOS
                WHERE
                   PRD_PREVTA >= ? AND
                   PRD_PREVTA <= ?';

   FOR EXECUTE STATEMENT
      (lcComando) (tnPrecio1, tnPrecio2)
   INTO
      :ftcNombre,
      :ftnPrecio
   DO BEGIN
      SUSPEND;
   END

END;

En este caso, el primer signo de interrogación dentro de lcComando es reemplazado por el primer parámetro enviado. El segundo signo de interrogación por el segundo parámetro y así sucesivamente. Por lo tanto aquí sí importa el orden en el cual enviamos los parámetros. Si enviamos los parámetros con el orden equivocado (es decir: primero tnPrecio2 y después tnPrecio1) entonces obtendremos un resultado erróneo.

Conclusión:

Poder enviarle parámetros al comando que ejecutamos con EXECUTE STATEMENT es muy útil y nos permite escribir código fuente más confiable.

En general es preferible enviar parámetros con nombres porque eso disminuye la probabilidad de cometer errores. Además, si un parámetro se usará varias veces dentro de lcComando con enviarlo una sola vez será suficiente.

La ventaja de enviar los parámetros por posición es que se escribe menos. La desventaja es que si equivocamos el orden de los parámetros enviados el resultado que obtendremos será erróneo. Y si un parámetro se necesita varias veces tendremos que enviarlo varias veces.

La opción de concatenar los parámetros es la menos recomendable porque cuando lcComando es largo y recibe varios parámetros tantas concatenaciones pueden marear a cualquiera

Artículos relacionados:

EXECUTE STATEMENT

El índice del blog Firebird21