Calculating age from dob in PostgreSQL using trigger [closed] - postgresql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am trying to calculate the age of a person when a record is inserted or updated in table staff but somehow the below trigger function does not work:
create or replace function Age()
returns trigger as $body$
declare
dob1 date;
age1 integer;
BEGIN
select dob into dob1 from staff;
select age(current_date,dob) into age1;
update staff set age=age1;
END; $body$ language plpgsql;
create trigger trig_age
before insert or update on staff
FOR EACH ROW
execute procedure age();
I'm not sure about this above code. I want a trigger to calculate and insert the AGE when inserting DOB in some table

First of all, the name of the trigger function may not be the most appropriate. There is already an overloaded regular function by that name and while the parameters differ and PostgreSQL will therefore accept it, you might confuse whomever has to work with your code.
Otherwise you are not far off. The principal change is that you should not call an UPDATE in a trigger function for the same table that the trigger is fired for: you may get an infinite loop. Just use assignments to the NEW implicit parameter. Since you obviously want the age in years of a person, you should get that specific date_part() into field age.
CREATE OR REPLACE FUNCTION age_in_years() RETURNS TRIGGER AS $body$
BEGIN
NEW.age := date_part('year', CURRENT_TIME - NEW.dob::timestamp);
RETURN NEW; -- or the insert or update would fail
END;
$body$ LANGUAGE plpgsql;
Setting the values in the NEW parameter and returning that parameter at the end of the function will change the values that will be inserted or updated into the table.
However, a person's age may change in between updates so you are probably better off dropping the column age from table staff (and thus also the trigger) and then creating a view that calculates the age whenever that view is accessed:
CREATE VIEW staff_today AS
SELECT *, date_part('year', CURRENT_TIME - dob::timestamp) AS age
FROM staff;
Like so you will always get the correct age.

Related

Function to Automatically set number of corresponding records in one table as default value in second table

I'm kind of stuck here. I'll try to keep it simple.
I have two tables.
Products (product_id, number_of_reviews, ...)
Reviews (main_product_id, review, ...)
main_product_id in Reviews table is the foreign key referencing product_id of Products table.
I need that the number_of_reviews column should automatically update to the number of reviews for that product_id present in the Reviews table. Match can be made by comparing product_id with main_product_id.
I know that I can use count to get number of reviews using this sql statement like:
SELECT COUNT(*) FROM reviews WHERE main_product_id = 'exampleid1'
Here exampleid1 should be product_id from products table.
But how do I create the function that I can call for DEFAULT in column number_of_reviews? Function that automatically takes the product_id from current row and passes it to that select statement and return the number of reviews...
I'm just so stuck here from hours, did a lot of searching but I can't figure it out.
It is my first time asking a question here on stackoverflow and my first time I'm taking interest in coding. PERN stack to be specific.
(I didn't like code for more than 6 years but now finally i built some interest)
First off this is actually a bad plan, you are saving a value the can easily be calculated. However, it seems quite common even though it often leads to complications. The function you need is a trigger; more specifically a trigger function and a trigger on reviews. (see demo)
create or replace function record_a_review_air()
returns trigger
language plpgsql
as $$
begin
update products
set reviews = reviews+1
where prod_id = new.prod_id;
return new;
end;
$$;
create trigger reviews_air
after insert
on reviews
for each row
execute function record_a_review_air();
NOTE: Setting a DEFAULT will not accomplish what you want. Doing so would set the a value when the Product is inserted. But would never be invoked again for that Product.
Here is what worked for me - Thanks to the demo and code provided by #belayer
create or replace function record_a_review_air()
returns trigger
language plpgsql
as $$
begin
update products
set n_reviews = (SELECT COUNT(*) FROM reviews WHERE main_prod_id = prod_id)
where prod_id = coalesce(new.main_prod_id, old.main_prod_id);
return new;
end;
$$;
create trigger reviews_air
after insert or delete or update of rev_id, main_prod_id, review
on reviews
for each row
execute function record_a_review_air();
(I updated the answer to add the new code that works for me on events(insert, update, delete) )

Creating a trigger function in SQL

I've been given a task to create a trigger function for this question:
Add an update to the support ticket from a given staff member. If the ticket is closed no more updates should be allowed by either customers or staff members.
Insert an update to a ticket with values: ticketUpdateID = 10050; Message ='Highlight folder for backup and press to trash or right click and choose delete'; TicketID = 1010 ; StaffID=2
All I've managed so far is:
CREATE OR REPLACE FUNCTION update_ticket()
RETURNS trigger AS $BODY$
BEGIN
I would just like to know the layout of what i would have to put next.
Thanks
The question becomes "How do you want to handle bypassing the update: silently ignore the action or raise an exception"? Postgres provides for both cases. The trigger function for an Update DML receives 2 pseudo rows conveniently named old and new (at least by default) which represent the current database row and the "tobe" database row respectively. Somewhere in the table definition you have some column indicating the current status of the some value indicating "closed". Unfortunately you have not defined either so I will just make something up for demo purpose. The following will suppress the any update on a 'closed' ticket. I will leave Raising an exception for your research.
create or replace
function update_ticket()
returns trigger
language plpgsql
as $$
begin
if old.status = 'closed' then
return null;
end if;
return new;
end;
$$;

Create a trigger update [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Create a trigger that automatically when inserting data into the builds_result table updated the value of the updated_time field of the apps table to the current date and time. Error is given in on apps.updated_time
create trigger upd after insert
on builds_result
for each row
execute procedure new apps.updated_time = now();
Here's a brief overview of how to setup a trigger.
First create the trigger function:
CREATE OR REPLACE FUNCTION my_trigger_function()
RETURNS TRIGGER AS
$BODY$
BEGIN
UPDATE apps
SET updated_time = NOW();
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql;
It's very simple, just updates the table (notice it will update all records, this is simply because you haven't said which particular record should be updated) and returns NEW, which is the record that was inserted in builds_result.
Then you create a trigger on the builds_result table to execute this function:
CREATE TRIGGER upd
AFTER INSERT ON builds_result
FOR EACH ROW
EXECUTE PROCEDURE my_trigger_function();
That's it. Now that trigger function will be called every time a row is inserted into the builds_result table.

Insert %rowtype data into another table - plpgsql / Postgres [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have one table called empl, and have another table new_empl with the same columns and definition with empl. Is it possible to insert records from v_record in new_empl using the following code ?
DECLARE
v_record empl%rowtype;
BEGIN
Insert into new_empl values v_record;
END;
There are too many columns in empl table and I want to avoid listing them.
The above snippet would work for Oracle, but for Postgres/pgplsql, the following snippet works like a charm:
DECLARE
v_record empl%rowtype;
BEGIN
Insert into new_empl values (v_record.*);
END;
Is it possible to insert records from v_record in new_empl using the
following code
Yes its possible however the way you are doing insert will not insert anything as nothing to assigned to the variable v_record . Rather you can do something like below:
DECLARE
v_record empl%rowtype;
BEGIN
Insert into new_empl Select * from empl;
END;
But why you want to do it in a PLSQL block when you can do it SQL itself.
Insert into new_empl select * from empl;

Subquery in pl/pgsql is not worked [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have function in pl/pgsql in postgresql
ie
CREATE or replace FUNCTION check_checklist_is_finalizedtest(application_id bigint)
RETURNS SETOF record AS
$BODY$
DECLARE
sqlresult record;
val boolean:=false;
BEGIN
for sqlresult in execute IMMEDIATE 'select distinct mda.application_id maid,mda.document_type_id mdoctypeid,
dt.multiple_doc dtmdoc,mda.mandatory_doc_application_id mdocaid,COALESCE(ac.doc_correct,false) doccorrect,
COALESCE((select max(e_certificate_no) from application_document ad
where ad.application_id=mda.application_id and ad.document_id=mda.document_type_id and multiple_doc=true and ad."valid"=''||New||''
),'''||1||''')as no_of_docs,
(select count(*) from application_document ad2
where ad2.application_id=mda.application_id and ad2.document_id=mda.document_type_id and ad2."valid"=''||New||''
)as count_of_record
from mandatory_doc_application mda
inner join document_type dt on(mda.document_type_id=dt.document_id)
left join application_checklist ac on(ac.man_doc_app_id= mda.mandatory_doc_application_id)
where mda.application_id='''||$1||''''
LOOP
IF(sqlresult.no_of_docs::bigint=sqlresult.count_of_record and sqlresult.doccorrect=true) then
val=true;
ELSE
val=false;
END IF;
return next sqlresult;
END LOOP;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
When function is called subqueries in select statement are not executed.Hence the result is wrong.Can you help me?
Probably something went wrong translating your query to dynamic SQL. The code in your question is very hard to read, which increases the risk of errors.
This strange expression probably does not what you think it does:
and ad2."valid"=''||New||''
You expect a variable New, but it is not declared and you use a constant string there instead.
Next strange thing: the key word IMMEDIATE - PostgreSQL doesn't support it - so your code cannot be compiled probably.
Questions:
Why do you use a dynamic SQL? There doesn't seem to be need for that.
If you use a dynamic SQL, why you don't use a modern form like
FOR r IN EXECUTE 'SELECT * FROM tab WHERE somecol = $1' USING $1
LOOP ...
But your code would be simpler and faster with plain SQL:
BEGIN
RETURN QUERY SELECT no_of_docs::bigint=count_of_record
AND COALESCE(ac.doc_correct,false) = true
FROM ...;
RETURN;
END;
Remember to only select columns that you actually need to return - not others.