En general, quienes recién empiezan a usar Firebird entienden bastante bien el concepto de stored procedure, después de todo es lo mismo que una rutina, procedimiento o función en el lenguaje de programación que están acostumbrados a usar (Visual FoxPro, Visual Basic, Delphi, C, C++, Java, etc.).
Sin embargo, suelen tener dificultades en entender a los triggers, así que aquí explicaremos en que se asemejan y en que se diferencian.
Semejanzas:
- Ambos son código fuente que escribimos dentro de la Base de Datos
- En ambos podemos usar excepciones
- En ambos podemos usar las operaciones: INSERT, UPDATE, DELETE, SELECT
- En ambos podemos usar EXECUTE PROCEDURE
- En ambos se pueden escribir comentarios
Diferencias:
- A los stored procedures se los debe llamar explícitamente con el comando EXECUTE PROCEDURE o con el comando SELECT. Los triggers son invocados automáticamente por el Firebird
- Los triggers disponen de dos seudo-variables llamadas NEW y OLD. Con NEW sabemos cual es el valor que se guardará en una columna, con OLD conocemos cual es el valor que actualmente está guardado en esa columna
- En los triggers tenemos tres variables de tipo boolean, llamadas: INSERTING, UPDATING, DELETING, las cuales nos permiten saber si el trigger fue lanzado durante una operación de inserción, de actualización o de borrado
- Los stored procedures pueden no recibir parámetros de entrada, recibir un solo parámetro de entrada, recibir muchos parámetros de entada. Los triggers no reciben parámetros de entrada
- Los stored procedures pueden no devolver valores, devolver un solo valor, devolver muchos valores. Los triggers nunca devuelven valores
- Para determinar en que orden se ejecutarán los triggers se usa la variable POSITION que puede valer 0, 1, 2, 3, 4, …, etc. Primero se ejecuta el trigger que tiene POSITION = 0, luego el que tiene POSITION = 1, y así sucesivamente
Ejemplo de stored procedure:
Listado 1.
CREATE PROCEDURE EXISTE_NUMERO_NOTA_CREDITO( tcCodSuc TYPE OF COLUMN MOVIMCAB.MVC_CODSUC, tcNotCre TYPE OF COLUMN MOVIMCAB.MVC_NOTNRO) RETURNS( ftlDocumentoExiste TYPE OF D_BOOLEAN) AS DECLARE VARIABLE lcNumero TYPE OF COLUMN MOVIMCAB.MVC_NOTNRO; BEGIN SELECT COALESCE(M.MVC_NOTNRO, '') FROM MOVIMCAB M WHERE M.MVC_CODSUC = :tcCodSuc AND M.MVC_TIPMOV = 'NCR' AND M.MVC_NOTNRO = :tcNotCre INTO :lcNumero; ftlDocumentoExiste = 'F'; IF (tcNotCre = lcNumero) THEN ftlDocumentoExiste = 'T'; END
En este stored procedure tenemos:
- Dos parámetros de entrada (tcCodSuc y tcNotCre)
- Un parámetro de salida (ftlDocumentoExiste)
- Una variable interna del stored procedure (lcNumero)
Ejemplo de trigger:
Listado 2.
CREATE TRIGGER DEPARTAMENTOS_BI FOR DEPARTAMENTOS ACTIVE BEFORE INSERT OR UPDATE POSITION 1 AS BEGIN IF (NEW.DEP_IDENTI IS NULL OR NEW.DEP_IDENTI <= 0) THEN EXCEPTION E_SIN_IDENTIFICADOR; IF (NEW.DEP_CODIGO IS NULL OR CHAR_LENGTH(TRIM(NEW.DEP_CODIGO)) = 0) THEN EXCEPTION E_SIN_CODIGO; IF (NEW.DEP_NOMBRE IS NULL OR CHAR_LENGTH(TRIM(NEW.DEP_NOMBRE)) = 0) THEN EXCEPTION E_SIN_NOMBRE; END
Este trigger valida las columnas que se quieren insertar o actualizar en la tabla de DEPARTAMENTOS, impidiendo que ocurra la inserción o actualización cuando la columna DEP_IDENTI es nula o es cero, la columna DEP_CODIGO es nula o está vacía, la columna DEP_NOMBRE es nula o está vacía.
Como el trigger es BEFORE INSERT OR UPDATE será lanzado automáticamente cada vez que se quiera insertar o actualizar alguna fila de la tabla de DEPARTAMENTOS.
O sea que si escribimos:
INSERT INTO DEPARTAMENTOS VALUES(0, 1, ‘PRUEBA’);
el Firebird lanzará el trigger. También lo lanzará si escribimos algo como:
UPDATE DEPARTAMENTOS SET DEP_NOMBRE = ‘Otra prueba’ WHERE DEP_IDENTI = 123;
Artículos relacionados:
Entendiendo a los stored procedures
El índice del blog Firebird21 | Firebird SQL
Jun 28, 2013 @ 22:36:00
Sep 02, 2015 @ 15:56:53
Hola Walter Buenas Tarde.
Disculpa tengo una duda acerca de los triggers, veras estoy trabajando con una aplicación que no es mia y esta conectada a una BD de firebird que no tiene sus id’s autoincrementables, usan un Trigger para actualizar los ids de todas las tablas (Como en un articulo que tu explicaste acerca de usar un unico generador para todas las tablas),
el problema me surge cuando trato de hacer una insercion manual no desde la aplicacion, ya que la aplicacion desconozco el proceso que haga que me actualiza el id, pero si lo hago manual no me puede actualizar el id y usar ese generador, entiendo que yo no puedo llamar al Trigger, que solo se invoca pero no consigo que me genere un id para el registro nuevo que quiero insertar
por ejemplo el valor de mi generador va en 5500, cuando guarde el registro con
Insert into almacen (articulo_nom, existencia, precio) values(‘Agua embotellada’, 500, 12);
no inserto ningun valor en el id pero me manda un error al hacerlo, el codigo del trigger es mas o menos asi:
CREATE OR ALTER TRIGGER DOCTOS_ALMACEN FOR ALMACEN
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.DOCTO_ALMACEN_ID = -1) THEN
NEW.DOCTO_ALMACEN_ID = GEN_ID(ID_DOCTOS,1);
END
Y ID_DOCTOS tiene el valor 5500
Alguna idea ?? Muchas gracias por tu tiempo
Saludos desde México
Sep 02, 2015 @ 16:41:33
Evidentemente el generador se incrementa cuando la columna DOCTO_ALMACEN_ID vale -1
Debes poner esa columna también en tu INSERT.
Saludos.
Walter.
Sep 02, 2015 @ 16:44:57
Gracias por todo lo pruebo entonces gracias
Saludos
May 18, 2017 @ 15:34:37
Buen dia mis estimados, me pasa lo mismo que flako, ya use la solución de insertar con -1 y funciona solo quiero verificar que sea correcto ya que no me da buena espina que se eleve tanto el ID, por ejemplo, yo tengo en mis ids (que se han insertado con el programa base)
CFD_RECIBIDO_ID
620,199
712,158
y cuando uso esa solución
query que se ejecuta manualmente
insert into cfd_recibidos
(cfd_recibido_id, clave_sistema, docto_id, fecha, xml, cfdi_id)
values
(-1, ‘CM’, 619976, ‘2016-03-09’, ‘PRUEBA’,626365)
el id me lo deja en
5,716,696, es normal tanta diferencia?
dejo igual el trigger para ver lo que hace (este lo ejecuta en Before Insert)
AS
BEGIN
IF (NEW.CFD_RECIBIDO_ID = -1) THEN
NEW.CFD_RECIBIDO_ID = GEN_ID(ID_DOCTOS,1);
END
de antemano saludos y gracias