Hola misol_108,
Creo que en realidad vamos comprendiendo. ¡A no desesperarse!
Veamos, en PostgreSQL existen los stored procedures (o procedimientos almacenados) que se declaran como una función como la que tu defines. A los triggers en PostgreSQL se les llama triggers procedures porque se declaran en dos partes: primero el procedimiento almacenado que contendrá la rutina del trigger y por el otro lado la declaración propia del trigger. El trigger lo que hace es invocar al procedimiento almacenado vinculado a éste; allí acaba la ciencia y que genera la confusión.
Ahora bien, un procedimiento almacenado puede regresar, o no, un conjunto de datos a modo de resultado. Las operaciones dentro de un SP (abreviatura en inglés) pueden involucrar a muchas tablas. Distinto es cuando estamos haciendo un trigger, el procedimiento para el trigger regresa realmente un resultado y sólo tiene la posibilidad de operar sobre la propia tabla en la que se defina.
En otros motores de bases de datos, y en términos conceptuales, los conceptos de trigger y stored procedure son independientes. Hago esta aclaración porque en términos prácticos, PostgreSQL incurre en un error de concepto al "vender" el concepto de trigger procedures y me temo que Oracle también si es que funciona igual.
Ahora yendo a tus dudas, como dije: es necesario bajar a tierra la idea y objetivo que persigues de esto. ¿A que requisito u objetivo de contexto o negocio apunta la funcionalidad que estás proponiendo? Es decir, sin entrar en los detalles de desarrollo e implementación ¿Cuál es el objetivo a conseguir?
Esto es fundamental para determinar las posibles alternativas.
Tu dices:
creo mi tabla la puedo llenar si en tal caso quiero ver los datos
Pregunto: ¿Tiene alguna utilidad o necesidad disponer realmente de los campos, por darles nombre Monto12, Monto24 y Monto32 en la tabla? ¿Se los utilizará en algún lado esta información? ¿Para que?
¿Necesitas realmente estos campos?
A. Si en realidad tus requisitos y necesidades te están diciendo que esos datos tienen una utilidad real y operatoria y se los usa en otro lugar entonces si vale la pena almacenarlos.
B. Si tus requisitos te dicen que en realidad sólo es a efectos de visualización o presentación entonces podemos calcularlos y mostrarlos sin necesidad de tenerlos físicamente.
Si tu caso se inclina a la opción A entonces SI crea los campos para la tabla. Ahora como ya dispones de esos campos podemos preveer una alternativa basada en el uso de los trigger procedures. Explicaré, o trataré mejor dicho, de exponer un ejemplo de esto más adelante como para que te hagas una idea. No uso postgreSQL por lo que no puedo garantizar de que funcione del todo; pero al menos dará una clara idea de por donde van las cosas.
Si tu caso se inclina a la opción B, para presentar la información solicitada tenemos más alternativas:
B1. Mandar a ejecutar desde la aplicación una consulta simple que los calcule:
SELECT monto_couta, (monto_couta * 12) AS Monto12, (monto_couta * 24) as Monto24, (monto_couta * 32) as Monto32, ...
FROM solicitud
Esto es SQL estándar y funciona en todo motor de base de datos. Luego tu aplicación muestra los datos en una rejilla o grid o los controles que tu dispongas.
B2. Tener un procedimiento almacenado seleccionable. Es decir, un procedimiento almacenado (nota que no hablo de un trigger procedure) que devuelva un conjunto de datos a modo de resultado. Contar con esta opción permite que dentro del procedimiento se hagan otras operaciones de interés, y de valor de negocio. Para hacer uso de estos procedimientos se invoca de forma similar a una consulta. De hecho un procedimiento almacenado seleccionable ES una consulta:
SELECT * FROM NombreProcedimientoSeleccionable()
B3. Tener una vista, que es como una consulta pero que en vez de ser ejecutada desde el cliente queda guardada en la base de datos. Luego la aplicación manda a ejecutar la consulta y puede mostrar este dato. Este tema no lo abordaré por considerarlo que se sale de tópico y complicaría las cosas. De todas formas recomiendo la lectura sobre las Vistas (VIEW).
Volvamos al caso A. Al final comentaste esto:
y despues es que creo el disparador par que cuando se inserte un nuevo monto en la tabla me haga los calculo
Si sólo nos debiéramos guiar por esto entonces todos te diríamos que es necesario definir un stored procedure CalcularMontos y un trigger que lo mande a ejecutar, CalcularMontos por darles un nombre.
Para este caso obviamente necesitamos de los campos necesarios en la tabla. Según el supuesto, el usuario va a ingresar un registro en la tabla solicitud. De ese registro llena el campo monto_cuota y el sistema por si mismo le calculará y llenará los restantes. Eso es lo que da a entender, si necesitas vamos:
1) Definir el procedimiento del trigger. Yo lo he llamado calcular_montos():
CREATE OR REPLACE FUNCTION calcular_montos() RETURNS TRIGGER AS $calcular_montos$
DECLARE
BEGIN
NEW.monto_cuota_12 := NEW.monto_couta * 12;
NEW.monto_cuota_24 := NEW.monto_couta * 24;
NEW.monto_cuota_32 := NEW.monto_couta * 32;
RETURN NEW;
END;
$calcular_montos$ LANGUAGE plpgsql;
Observa que este procedure tiene en su declaración RETURNS TRIGGER. Esta es la manera que tiene PostgreSQL de indicarle al motor que se trata de un procedimiento asociado a un trigger.
Fíjate que hago uso de una variable llamada NEW. Esta variable NEW la tienen todos los motores de datos, es una variable implícita que representa a un nuevo registro que se va a insertar o bien a un registro que se va a actualizar en al menos un campo por un nuevo valor. Así como existe NEW, existe OLD que como se puede deducir representa a un registro que se va a eliminar, o bien, al registro con los valores viejos que se van a reemplazar.
Es fundamental prestar atención a esas dos variables ya que las vas a encontrar en todos los triggers.
Así como existen NEW y OLD hay otras más. En los enlaces que puse hay un listado.
Fíjate que en el ejemplo yo hago NEW.campo para acceder al campo es cuestión. Por tanto si hago NEW.monto_cuota_12 := NEW.monto_cuota * 12 lo que estoy haciendo es establecer en el campo monto_cuota_12 del nuevo registro a insertar el valor de monto_cuota multiplicado por 12.
Al final del cuerpo del procedure puede verse un RETURN NEW. Esto le indica que "confirme" los cambios sobre el registro nuevo y los almacene en la tabla.
Vamos ahora a definir el trigger:
CREATE TRIGGER calcular_montos BEFORE INSERT
ON solicitud FOR EACH ROW
EXECUTE PROCEDURE calcular_montos();
Vemos en su declaración un BEFORE INSERT. Esto quiere decir que el disparador se dispará justo antes de insertarse un registro en la tabla solicitud.
Vemos además que se estableció el nivel de alcance, con FOR EACH ROW. Esto indica que por cada registro que se inserte debe ejecutar el procedimiento almacenado calcular_montos().
Entonces, ahora cada vez que tu mandes a ejecutar una sentencia INSERT sobre dicha tabla, el motor disparará el tigger que éste ejecuta el procedimiento y finalmente se inserta el registro con los valores de los montos de las cuotas calculados.
Nota que en realidad el caso A y B pueden convivir sin problemas y no necesariamente son mutuamente excluyentes. Las necesidades y requisitos de negocio te deben ir aportando la información necesaria para que tomes las decisiones e implementaciones prácticas más adecuadas a cada caso. Por regla general los valores que pueden ser recalculados no se almacenan; aunque hay ocasiones, y por cuestiones de diseño, en que si se deben almacenar (por ejemplo en los casos de tablas de auditorías).
Espero haberte sido de ayuda en algo. Recomiendo que dediques parte de tu tiempo a familiarizarte con los conceptos y de la PL/pgSQL.
Saludos,