Why this trigger is not inserting records in my table in postgres? - postgresql

Here are my 3 tables.
Booking(Bookingid,date_of_booking,groupid,packageid,price)
Passenger(passengerid,groupid)
package(packageid,type)
Here is a function which will be called when trigger gets executed.
CREATE OR REPLACE FUNCTION COUNTPRICEFORTICKET3()
RETURNS TRIGGER AS
$$
DECLARE
MYID INTEGER;
MYPRICE DOUBLE PRECISION;
BEGIN
SELECT COUNT(*) AS CNT INTO MYID FROM PASSENGER WHERE GROUPID=NEW.GROUPID
GROUP BY GROUPID;
SELECT PRICE INTO MYPRICE FROM PACKAGE WHERE PACKAGEID=NEW.PACKAGEID;
NEW.PRICE:=MYPRICE * MYID;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER COUNTPRICE3 BEFORE INSERT ON BOOKING
FOR EACH ROW EXECUTE PROCEDURE COUNTPRICEFORTICKET3();
The problem is that trigger is executed successfully but when I try to insert records to booking table using INSERT query like this, it does not insert record.
INSERT INTO BOOKING VALUES(NEXTVAL('BOOKSQ'),'26-SEP-2018',1201,700,NULL);

Related

How do I update a summary table with a trigger?

I am working with the sample DVD_Rental database. I have to create a trigger on my category_performance_details table that will create a summary table every time data is added to the detail table.
These are the queries I am using to setup my tables:
DROP TABLE IF EXISTS category_performance_summary;
CREATE TABLE category_performance_summary (
genre VARCHAR(25),
total_sales numeric
);
DROP TABLE IF EXISTS category_performance_details;
CREATE TABLE if not exists category_performance_details (
category_id Int,
category_name VARCHAR(25),
film_id Int,
film_title VARCHAR(255),
film_rental_rate numeric(4,2),
inventory_id Int,
payment_id Int,
payment_amount numeric(4,2),
rental_id Int,
rental_date Timestamp
);
I want to update the summary table after every insert statement with a trigger so that it provides a summary of the total sales per category. Basically, the summary table should be the same result as:
SELECT category_name, SUM(payment_amount) FROM category_performance_details
GROUP BY category_name;
This is my procedure and trigger. For some reason, I am getting a syntax error at or near "CREATE TRIGGER". Am I approaching this trigger correctly? What is wrong with my syntax?
CREATE OR REPLACE FUNCTION update_summary_table()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
TRUNCATE TABLE category_performance_summary;
INSERT INTO category_performance_summary (genre, total_sales)
SELECT category_name, SUM(payment_amount)
FROM category_performance_details
GROUP BY category_name;
RETURN NEW;
END;
$$
CREATE TRIGGER update_summary
AFTER INSERT
ON category_performance_summary
FOR EACH STATEMENT
EXECUTE PROCEDURE update_summary_table();
You can also simply increment or decrement the total_sales in the trigger function.
In any case you have to use the NEW (resp. OLD) key word in order to refer to the values that are inserted/updated (resp. deleted) in table category_performance_summary :
CREATE OR REPLACE FUNCTION increment_summary_table()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
INSERT INTO category_performance_summary (genre, total_sales)
VALUES (NEW.category_name, 1)
ON CONFLICT (genre) DO UPDATE
SET total_sales= total_sales + 1
WHERE genre= NEW.category_name ;
RETURN NEW;
END;
$$ ;
CREATE TRIGGER increment_summary
AFTER INSERT
ON category_performance_summary
FOR EACH STATEMENT
EXECUTE PROCEDURE increment_summary_table();
CREATE OR REPLACE FUNCTION decrement_summary_table()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
UPDATE category_performance_summary
SET total_sales= total_sales - 1
WHERE genre= OLD.category_name ;
RETURN OLD;
END;
$$ ;
CREATE TRIGGER decrement_summary
AFTER DELETE
ON category_performance_summary
FOR EACH STATEMENT
EXECUTE PROCEDURE decrement_summary_table();

how to get the result of the select query and pass it as a input to delete query in Function Postgresql

CREATE OR REPLACE FUNCTION test(name VARCHAR (255))
RETURNS INTEGER AS
$BODY$
DECLARE
emp_id INTEGER;
BEGIN
SELECT employee.employee_id into emp_id from employee where first_name = name;
DELETE FROM employee WHERE employee_id = emp_id;
return emp_id;
END
$BODY$
LANGUAGE plpgsql;
when i call the function its deleting all the records in my employee table.
First store value in a variable for given input and these execute delete command with this variable and return this variable.
-- PostgreSQL
-- create table and store data
create table employee (emp_id int, name varchar(255));
insert into employee values (1, 'Rahul'), (2, 'Biswas'), (3, 'Shuva');
-- create function
CREATE OR REPLACE FUNCTION test(p_name varchar(255))
RETURNS INTEGER AS
$BODY$
DECLARE v_emp_id INTEGER;
BEGIN
SELECT e.emp_id into v_emp_id from employee e where e.name = p_name;
DELETE FROM employee WHERE emp_id = v_emp_id;
return v_emp_id;
END
$BODY$
LANGUAGE plpgsql;
-- execute function
select * from test('Rahul');
Please check this url https://dbfiddle.uk/?rdbms=postgres_11&fiddle=4c134787dafd8fe58b032d700168318d

Postgresql query across different tables with dynamic query

I'm trying to get a customer id which can be placed in one of ten different tables. I don't want to hard code those table names to find it so I tried postgresql function as follows.
create or replace FUNCTION test() RETURNS SETOF RECORD AS $$
DECLARE
rec record;
BEGIN
select id from schema.table_0201_0228 limit 1 into rec;
return next rec;
select id from schema.table_0301_0331 limit 1 into rec;
return next rec;
END $$ language plpgsql;
select * from test() as (id int)
As I'm not familiar with postgresql function usage, how can I improve the code to replace 'schema.table1' with a variable, loop each table and return the result?
NOTE: table names may change overtime. For example, table_0201_0228 and table_0301_0331 are for February and March respectively.
You need dynamic SQL for that:
create or replace FUNCTION test(p_schema text)
RETURNS table(id int)
AS $$
DECLARE
l_tab record;
l_sql text;
BEGIN
for l_tab in (select schemaname, tablename
from pg_tables
where schemaname = p_schema)
loop
l_sql := format('select id from %I.%I limit 1', l_tab.schemaname, l_tab.tablename);
return query execute l_sql;
end loop;
END $$
language plpgsql;
I made the schema name a parameter, but of course you can hard-code it. As the function is defined as returns table there is no need to specify the column name when using it:
select *
from test('some_schema');

Postgresql Trigger to insert rows

I'm stuck for days with triggers on Postgresql (and Mysql as well). I just want to insert newly filled rows to another table. The original data comes from an external form (OpenDataKit) and goes to "intermediate" tables. I can't understand why the form cannot send the data anymore once the trigger is created... Note that all actions work without the trigger, when I do the insertions by hand. I would greatly appreciate some help to understand what I am doing wrong. I am now testing with Postgresql 9.5, but I got similar issue with MySQL 5.1.
-- CREATE procedure:
CREATE OR REPLACE FUNCTION proc_natobs() RETURNS TRIGGER AS
$BODY$
DECLARE
BEGIN
INSERT INTO lieu (id_lieu, wgs_lat, wgs_lon, date_obs, geom)
SELECT id_loc,"GPS_TEL_LAT", "GPS_TEL_LNG", "DATE_OBS", ST_SetSRID(ST_POINT("GPS_TEL_LNG","GPS_TEL_LAT"), 4326)
FROM "FORMULAIRE_NATOBS_REPEAT_LOC", "FORMULAIRE_NATOBS_CORE"
WHERE "FORMULAIRE_NATOBS_CORE"."_URI" = "FORMULAIRE_NATOBS_REPEAT_LOC"."_TOP_LEVEL_AURI"
AND "FORMULAIRE_NATOBS_REPEAT_LOC".id_loc IN (SELECT max(id_loc) FROM "FORMULAIRE_NATOBS_REPEAT_LOC");
INSERT INTO i_lieu_observateurs (id_lieu, id_auteur)
SELECT id_loc, CAST("AUTEUR" AS integer)
FROM "FORMULAIRE_NATOBS_CORE", "FORMULAIRE_NATOBS_REPEAT_LOC"
WHERE "FORMULAIRE_NATOBS_REPEAT_LOC"."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_CORE"."_URI"
AND id_loc IN (SELECT max(id_loc) FROM "FORMULAIRE_NATOBS_REPEAT_LOC")
UNION
SELECT id_loc, CAST("OBSERVATEURS" AS integer)
FROM "FORMULAIRE_NATOBS_REPEAT_LOC", "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"
WHERE "FORMULAIRE_NATOBS_REPEAT_LOC"."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"."_TOP_LEVEL_AURI"
AND id_loc IN (SELECT max(id_loc) FROM "FORMULAIRE_NATOBS_REPEAT_LOC")
;
END;
$BODY$
LANGUAGE 'plpgsql';
-- CREATE the trigger:
CREATE TRIGGER trigger_natobs AFTER INSERT
ON "FORMULAIRE_NATOBS_REPEAT_LOC"
FOR EACH ROW
EXECUTE PROCEDURE proc_natobs();
So, when the ODK form inserts new rows in FORMULAIRE_NATOBS_REPEAT_LOC (for which I have created a serial ID to facilitate the SQL queries), I try to insert this row (combined with information from other intermediate tables) into table "lieu" for the first action of the trigger, and into table i_lieu_observation (composed by a double primary key) for the second action. I tested also with a trigger composed by the first action only, but it does not work either. The Android app that sends the form crashes until I remove the trigger.
Thanks in advance!
You need to use the special NEW variable in the trigger to access the newly inserted data. So you need something like:
CREATE OR REPLACE FUNCTION proc_natobs() RETURNS TRIGGER AS
$BODY$
DECLARE
BEGIN
INSERT INTO lieu (id_lieu, wgs_lat, wgs_lon, date_obs, geom)
SELECT new.id_loc,"GPS_TEL_LAT", "GPS_TEL_LNG", "DATE_OBS", ST_SetSRID(ST_POINT("GPS_TEL_LNG","GPS_TEL_LAT"), 4326)
FROM "FORMULAIRE_NATOBS_CORE"
WHERE "FORMULAIRE_NATOBS_CORE"."_URI" = new."_TOP_LEVEL_AURI";
INSERT INTO i_lieu_observateurs (id_lieu, id_auteur)
SELECT new.id_loc, CAST("AUTEUR" AS integer)
FROM "FORMULAIRE_NATOBS_CORE"
WHERE new."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_CORE"."_URI"
UNION
SELECT new.id_loc, CAST("OBSERVATEURS" AS integer)
FROM "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"
WHERE new."_TOP_LEVEL_AURI" = "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR"."_TOP_LEVEL_AURI";
RETURN new;
END;
$BODY$
LANGUAGE 'plpgsql';
-- CREATE the trigger:
CREATE TRIGGER trigger_natobs AFTER INSERT
ON "FORMULAIRE_NATOBS_REPEAT_LOC"
FOR EACH ROW
EXECUTE PROCEDURE proc_natobs();
Because I don't know which fields come from which tables, I cannot make the above totally correct. In the same way as I have written new.id_loc, you will need to put new.field_name for all fields coming from the formulaire_natobs_repeat_loc table.
HTH
Try this
CREATE OR REPLACE FUNCTION proc_natobs() RETURNS TRIGGER AS
$BODY$
BEGIN
IF(TG_OP = 'INSERT') THEN
INSERT INTO lieu (id_lieu, wgs_lat, wgs_lon, date_obs, geom)
SELECT id_loc,"GPS_TEL_LAT", "GPS_TEL_LNG", "DATE_OBS", ST_SetSRID(ST_POINT("GPS_TEL_LNG","GPS_TEL_LAT"), 4326)
FROM "FORMULAIRE_NATOBS_REPEAT_LOC" loc, "FORMULAIRE_NATOBS_CORE" core
WHERE core."_URI" = loc."_TOP_LEVEL_AURI"
AND loc.id_loc =new.id_loc;
INSERT INTO i_lieu_observateurs (id_lieu, id_auteur)
SELECT id_loc as id,
CAST("AUTEUR" AS integer) as auteur
FROM "FORMULAIRE_NATOBS_CORE" core, "FORMULAIRE_NATOBS_REPEAT_LOC" loc
WHERE loc."_TOP_LEVEL_AURI" = core."_URI"
AND loc.id_loc =new.id_loc;
UNION
SELECT id_loc as id,
CAST("OBSERVATEURS" AS integer) as auteur
FROM "FORMULAIRE_NATOBS_REPEAT_LOC" loc, "FORMULAIRE_NATOBS_REPEAT_OBSERVATEUR" obs
WHERE loc."_TOP_LEVEL_AURI" = obs."_TOP_LEVEL_AURI"
AND loc.id_loc =new.id_loc;
END IF;
Return new;
END;
$BODY$
LANGUAGE 'plpgsql';
-- CREATE the trigger:
CREATE TRIGGER trigger_natobs AFTER INSERT
ON "FORMULAIRE_NATOBS_REPEAT_LOC"
FOR EACH ROW
EXECUTE PROCEDURE proc_natobs();
Hope it work for you.

Postgresql : insert record using trigger

CREATE TABLE users
(
id integer NOT NULL DEFAULT nextval('userseq'::regclass)
........
)
CREATE TABLE History
(
userid integer,
createdat timestamp with time zone
)
CREATE OR REPLACE FUNCTION recordcreatetime()
RETURNS trigger AS
$BODY$
BEGIN
NEW.createdAt = NOW();
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
User and History has one-one relationship. How i can insert new record in History table before creating new user.
CREATE OR REPLACE FUNCTION recordcreatetime()
RETURNS trigger
language plpgsql
AS $$
DECLARE
BEGIN
INSERT INTO History values(new.id,NOW() );
RETURN NEW;
END;
$$;
and write trigger statement as
CREATE TRIGGER user_hist
BEFORE INSERT ON users
FOR EACH ROW EXECUTE function recordcreatetime() ;