Autoincrement field with trigger and sequence - Check if ID is in the statement [Postgres] - postgresql

I´ve got this sample from another thread and it fits perfectly on what I need to know.
CREATE SEQUENCE AlimentosSequencia;
CREATE TABLE alimento (
id integer NOT NULL PRIMARY KEY
,name VARCHAR(255));
CREATE OR REPLACE FUNCTION AlimentoFuncion()
RETURNS "trigger" AS
$BODY$
BEGIN
New.id:=nextval('AlimentosSequencia');
Return NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
CREATE TRIGGER AlimentosTrigger
BEFORE INSERT
ON alimento
FOR EACH ROW
EXECUTE PROCEDURE AlimentoFuncion();
INSERT INTO alimento (name) VALUES ('lemon');
This is working fine! But I have to complement the function AlimentoFunction.
Is there any way to check IN THE FUNCTION if my insert statement is placing an ID?
Example:
INSERT INTO alimento (name) VALUES ('lemon');
Ok this, works... and If I do that:
INSERT INTO alimento (id, name) VALUES (299, 'lemon');
My function must check if the sequence has to be used.
I know I can set the default value of ID to be the sequence on the table creation, but I can't modify that.. I just can change the trigger function.

Something like:
if new.id is NULL then
New.id:=nextval('AlimentosSequencia');
end if;

Related

Fill field based on column other table

I have a really simple problem and I am probably overthinking this way too much. But here it goes:
I want the fields of a column in one of my tables to be filled automatically whenever I make a new record. The value should be the same (UUID) as the specified (UUID) value from a column in another table. These two columns are joined via a foreign key. So far I have tried making a trigger function but with no results so far:
Create or replace function project_id()
returns trigger
as $$ begin
if new.project_id is null then
insert into sporen (project_id)
select project_id
from project_info
where project_code = 'ant0001';
end if;
return new;
end;
$$ language plpgsql;
CREATE TRIGGER
project_id_default
BEFORE update ON
sporen
FOR EACH ROW EXECUTE PROCEDURE project_id();
Do I need to specify something as a default in my table? Or am I going about it completely wrong?
You only need to assign project_info.project_id to NEW.project_id in your trigger function. No INSERT is needed. Here is an illustration.
Create or replace function project_id() returns trigger as
$$
begin
if new.project_id is null then
new.project_id :=
(
select pi.project_id
from project_info pi
where pi.project_code = NEW.project_code
);
end if;
return new;
end;
$$ language plpgsql;
You do not need to specify a default value for project_id in your table.

How to upsert with serial primary key

I have a stored procedure to perform an upsert. However the conflict condition never runs, passing an existing ID always causes it to create a new record.
create or replace function upsert_email(v_id bigint, v_subject character varying)
returns bigint
language plpgsql
as $$
declare
v_id bigint;
begin
insert into emails
(id, subject)
values (coalesce(v_id, (select nextval('serial'))), v_subject)
on conflict(id)
do update set (subject) = (v_subject) where emails.id = v_id
returning id into v_id;
return v_id;
end;
$$;
When running select upsert_email(6958500, 'subject'); which is a record that exists, it always creates a new record instead.
I have already looked at: Upsert/on conflict with serial primary key which is the most similar question and is what my SQL is modeled on, however I haven't been able to get it to work.
Wow, idiot of the year award goes to me.
I'm taking a parameter called v_id, then immediately overwrite it in the declare with a v_id; They should be named 2 different things:
create or replace function upsert_email(v_id bigint, v_subject character varying)
returns bigint
language plpgsql
as $$
declare
v_return_id bigint;
begin
insert into emails
(id, subject)
values (coalesce(v_id, (select nextval('serial'))), v_subject)
on conflict(id)
do update set (subject) = (v_subject) where emails.id = v_id
returning id into v_return_id;
return v_return_id;
end;
$$;

How to create trigger to insert a sequence of numbers in postgresql; but the insert statement validated before ..?

Good morning everyone, I have a question about the following case:
I have a trigger and a function that inserts a land code, but when it works very well when inserting a row.
But when an insert statement fails to execute for any problems in the expression, the sequence function generates a value before inserting the row, losing the order in the numeration.
There is a way to make a change in the trigger or function, to validate me before the INSERT expression before moving to the sequence function and thereby avoid those jumps of numeration.
Deputy code (triger and function) and images of the tables.
CODE:
CREATE TRIGGER trigger_codigo_pech
BEFORE INSERT ON independizacion
FOR EACH ROW
EXECUTE PROCEDURE codigo_pech();
CREATE OR REPLACE FUNCTION codigo_pech()
RETURNS trigger
AS $$
DECLARE
incremento INTEGER;
cod_inde text;
BEGIN
IF (NEW.cod_inde IS NULL OR NEW.cod_inde = '''' ) THEN
incremento = nextval ('codigo_pech');
NEW.cod_inde = 'PECH' || '-' || incremento;
END IF;
RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';
CAPTURE QUERY RESULT
As you can see, it would also be necessary to make a trigger on the primary key to prevent jumps in the numeration.
I hope your help. Thank you
You can make incremento.cod_inde DEFERRABLE and INITIALLY DEFERRED:
ALTER TABLE incremento ALTER COLUMN cod_inde SET DEFAULT 0;
ALTER TABLE incremento
ALTER CONSTRAINT incremento_cod_inde_key
DEFERRABLE INITIALLY DEFERRED;
Then assign the nextval('codigo_pech') in a AFTER INSERT trigger:
CREATE OR REPLACE FUNCTION codigo_pech_after() RETURNS trigger AS $$
BEGIN
UPDATE incremento SET
cod_inde = 'PECH-' || (nextval('codigo_pech'))::text
WHERE id = NEW.id; -- replace id with your table's primary key
END;
$$ LANGUAGE plpgsql;

Trigger insert into another table only if unique value

I have a trigger function that copy row of unique values to another table on update or insert that ALMOST work.
The trigger should only insert a new row to the sample table if the number don't exist in it before. Atm. it insert a new row to the sample table with the value NULL if the number already exist in the table. I dont want it to do anything if maintbl.number = sample.nb_main
EDIT: sample table and sample data
CREATE TABLE schema.main(
sid SERIAL NOT NULL,
number INTEGER,
CONSTRAINT sid_pk PRIMARY KEY (sid)
)
CREATE TABLE schema.sample(
gid SERIAL NOT NULL,
nb_main INTEGER,
CONSTRAINT gid_pk PRIMARY KEY (gid)
Example and desired result
schema.main schema.sample
number nb_main
234233 234233
234234 555555
234234
555555
555555
CREATE OR REPLACE FUNCTION schema.update_number()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO schema.sample(
nb_main)
SELECT DISTINCT(maintbl.number)
FROM schema.maintbl
WHERE NOT EXISTS (
SELECT nb_main FROM schema.sample WHERE maintbl.number = sample.nb_main);
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION schema.update_number()
OWNER TO postgres;
CREATE TRIGGER update_number
AFTER INSERT OR UPDATE
ON schema.maintbl
FOR EACH ROW
EXECUTE PROCEDURE schema.update_number();
I just found out that my select query is probably wrong, if I run SELECT query by itself it return one row 'NULL' but i should not?
SELECT DISTINCT(maintbl.number)
FROM schema.maintbl
WHERE NOT EXISTS (
SELECT nb_main FROM schema.sample WHERE maintbl.number = sample.nb_main);
Any good advice?
Best
If I understood correctly, you wish to append to schema.sample a number that has been inserted or updated in schema.maintbl, right?
CREATE OR REPLACE FUNCTION schema.update_number()
RETURNS trigger AS
$BODY$
BEGIN
IF (SELECT COUNT(*) FROM schema.sample WHERE number = NEW.number) = 0 THEN
INSERT INTO schema.sample(nb_main) VALUES (NEW.number);
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;

Not able to access the Primary Key value in PostgreSQL Trigger Function

I am just started writing the PL/pgSQL Trigger function. I am having couple of tables called Student and Result. Student having the following columns. ID,name,subject,mark (ID is the primary key) and the Result table is having two columns like ID,Status
Whenever one record has added in the student table, I want to update the Result table by checking the mark in the Student table, If the mark entered is greater than 50 then one record should be inserted in the Result table with ID and Status = Pass and if it is less than 50 then status will be fail.
I have the following Trigger function to achieve this
CREATE OR REPLACE FUNCTION "UpdateResult"() RETURNS trigger AS $BODY$
BEGIN
IF NEW.mark < 50 THEN
INSERT INTO "Result" SELECT 92,'fail';
RETURN NEW;
ELSE
INSERT INTO "Result" SELECT 92,'pass';
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE STRICT SECURITY DEFINER
COST 100;
ALTER FUNCTION "UpdateResult"() OWNER TO postgres;
CREATE TRIGGER "Result"
AFTER INSERT
ON "Student"
FOR EACH ROW
EXECUTE PROCEDURE "UpdateResult"();
By this function trigger has worked as expected since I have hard coded the primary key value.
But When I modify the SQL inside Trigger function like the following
INSERT INTO "Result" SELECT NEW.ID,'fail'; (or)
INSERT INTO "Result" SELECT NEW.ID,'pass';
It is throwing error like
> ***Record "new" has no field "id" Context : PL/pgSQL function
> "UpdateResult" line 3 at SQL statement***
Means it is able to take the values of non primary key values from NEW variable not the primary key value. Can any one please tell me is there a restriction in PL/pgSQL or Am I doing anything wrong !
Just a hint: why are you using quoted names? When doing this, you have to care about capitalisation.
See if this works:
CREATE OR REPLACE FUNCTION UpdateResult() RETURNS trigger AS $BODY$
BEGIN
IF NEW.mark < 50 THEN
INSERT INTO result (id, status) values (92,'fail');
RETURN NEW;
ELSE
INSERT INTO result (id, status) values (92,'pass');
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE STRICT SECURITY DEFINER
COST 100;
ALTER FUNCTION UpdateResult() OWNER TO postgres;
CREATE TRIGGER Result
AFTER INSERT
ON Student
FOR EACH ROW
EXECUTE PROCEDURE UpdateResult();