PostgreSQL trigger updating secondary related table - function

I have two tables: table1 and table2, which triggers on inserts and on updates in the same function.
As you insert a value in table1 or table2 a value is inserted in table3, with the value table1.lastname || table1.firstname assigned to column3. The id obtained for the insert in table3 must be inserted into table1.id_table3.
CREATE OR REPLACE FUNCTION myschema.myfunction() RETURNS trigger AS
$BODY$
DECLARE
new_id_table_4 integer;
BEGIN
IF TG_OP = 'INSERT' THEN
IF TG_TABLE_NAME = 'table1' THEN
new_id_table_4 := 1;
ELSIF TG_TABLE_NAME = 'table2' THEN
new_id_table_4 := 2;
END IF;
INSERT INTO myschema.table3
(id, id_table4, name)
VALUES (DEFAULT, new_id_table_4, NEW.columnA||', '||NEW.columnB, TRUE, TRUE)
RETURNING id
INTO NEW.id_table3;
ELSIF TG_OP = 'UPDATE' THEN
IF OLD.columnA <> NEW.columnA OR OLD.columnB <> NEW.columnB THEN
UPDATE myschema.table3 SET
name = NEW.columnA||', '||NEW.columnB
WHERE id = NEW.id_cuenta;
END IF;
END IF;
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
ALTER FUNCTION myschema.myfunction() OWNER TO myuser;
CREATE TRIGGER add_table3record_table1
AFTER INSERT OR UPDATE
ON myschema.table1
FOR EACH ROW
EXECUTE PROCEDURE myschema.myfunction();
CREATE TRIGGER add_table3record_table2
AFTER INSERT OR UPDATE
ON myschema.table2
FOR EACH ROW
EXECUTE PROCEDURE myschema.myfunction();
The problem is that when I insert a new record into table1 or table2,
...RETURNING id INTO NEW.id_table3;
It does not seem to have any effect.
This is my first function/trigger ever, and I cannot find the error.
Thank you!

I'm pretty sure you can't update a row AFTER it has already been inserted just by setting NEW.foo = bar.
Either:
Perform an update on the table1 setting the new id_table3 value (which is going to recursively call you ON UPDATE trigger, so be careful), or
Use a BEFORE trigger instead of an AFTER.
Depending on how your foreign keys are set up between table1 and table3, the latter may or may not be an option.

Related

Creating a trigger before insert

I am trying to update an entry if already exists using a trigger. I would like to check if an entry exists update if not then insert. When I tried to insert new entry I got an error: 'Can't update table in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
DELIMITER //
CREATE TRIGGER check_table_before_insert BEFORE INSERT ON Songs FOR EACH ROW BEGIN IF NEW.PageURL =(
SELECT
Songs.PageURL
FROM
Songs
WHERE
Songs.PageURL = NEW.PageURL
) THEN
UPDATE
Songs
SET
Songs.Title = NEW.Title,
Songs.Album = NEW.Album,
Songs.Label = NEW.Label,
Songs.Release_Date = NEW.Release_Date,
Songs.PageURL = NEW.PageURL,
Songs.IsSingle = NEW.IsSingle,
Songs.Code = NEW.Code,
Songs.ImageURL = NEW.ImageURL,
Songs.Link_320 = NEW.Link_320,
Songs.Link_128 = NEW.Link_128,
Songs.Link_48 = NEW.Link_48,
Songs.AlbumURL = NEW.AlbumURL
WHERE
Songs.PageURL = NEW.PageURL;
END IF;
END;
// DELIMITER;
This isn't an appropriate use for a trigger.
If you want to perform a "insert or update" operation on a table, use the INSERT … ON DUPLICATE KEY UPDATE … syntax. It already has the semantics you are looking for.
If the columns you are updating amount to the entirety of the row, you may be able to use the REPLACE verb as an alternative to INSERT. Note that it will delete the row before insetting a new one, so any columns not included in the REPLACE query will be lost.

Using triggers referring to different tables

I am trying to use a trigger so that it denies user entry if Boolean value from another table is unticked. How can I do this
TABLE A
IF
TABLE B attribute1 = 0 then, don't allow insert
TABLE B attribute1 = 1 then, allow insert
Sorry for the vauge description or zero code but I have no idea how to go about doing this
This should give you an starting point. Adjust table names and conditions according to your schema.
delimiter //
CREATE TRIGGER DENY_IF_TRUE
BEFORE INSERT ON [your table] FOR EACH ROW
BEGIN
DECLARE attr BOOLEAN;
-- 'set variable to attribute value
set #attr := (SELECT attribute FROM [your other table] WHERE [some condition] LIMIT 1);
IF #attr = TRUE THEN
-- 'this will make the trigger fail and therefore avoid the insert operation succeed'
CALL non_existent_function();
END IF;
END;
delimiter ;

After Insert Trigger terminate when error

I have an After Insert trigger which is supposed to insert first, then do insert another table. But when any error occurs for inserting data in another table the all transaction terminated. I want to insert 1st data in base table whether the trigger fire successfully or not.
This is my code:
CREATE TRIGGER [dbo].[Insert_Teacher_Active_LC]
ON [dbo].[Teacher_Profile]
AFTER INSERT,UPDATE
AS
BEGIN
MERGE [ROSC].[dbo].[Active_LC] as d
USING (SELECT
DistrictID, upazilaID, LCID, LCVisitYr, Trimister,
CASE WHEN (TcrPres = 1 AND TcrMtchLCProf = 1)
THEN 1 ELSE 0
END AS TcrRpls
FROM INSERTED) AS s ON s.DistrictID = d.DistrictID
AND s.upazilaID = d.upazilaID
AND s.LCID = d.LCID
AND s.LCVisitYr = d.EduYr
WHEN MATCHED THEN
UPDATE
SET Trimister = s.Trimister, Tcr_Replace = s.TcrRpls
WHEN NOT MATCHED THEN
INSERT(DistrictID, UpazilaID, LCID, EduYr, Trimister, Tcr_Replace)
VALUES(DistrictID, UpazilaID, LCID, LCVisitYr, Trimister, TcrRpls);
-- Insert statements for trigger here
END

IF NOT EXISTS in mysql showing syntax error

I am trying to convert this tsql to mysql but showing error need help
CREATE PROCEDURE FormAdd
#formName varchar(MAX)
AS
IF NOT EXISTS(SELECT * FROM tbl_Form WHERE formName=#formName)
BEGIN
INSERT INTO tbl_Form
(formName)
VALUES
(#formName)
SELECT ##identity
END
ELSE
BEGIN
SELECT '-1'
END
mysql
CREATE PROCEDURE FormAdd
(p_formName varchar(500) )
begin
INSERT INTO tbl_Form (formName)
VALUES (p_formName)
where NOT EXISTS(SELECT * FROM tbl_Form WHERE formName=p_formName) ;
SELECT Last_insert_id() as returnvalue ;
SELECT '-1' ;
end
Your attempt was syntactically invalid because logically, an INSERT statement cannot contain a WHERE clause since it does not act on existing rows.
If the purpose is to insert only if the value for p_formname is not already present, then an appropriate step would be to define a unique index on that column first. Then, construct your procedure to attempt the insert and inspect the ROW_COUNT() value to see if one was inserted and act accordingly, returning -1 if not to adapt your existing T-SQL procedure.
First create the unique index on p_formname:
ALTER TABLE tbl_Form ADD UNIQUE KEY `idx_formName` (`formName`);
Then your procedure should use INSERT INTO...ON DUPLICATE KEY UPDATE to attempt to insert the row. Per the documentation, the value of ROW_COUNT() will be 0 if a new row was not inserted or 1 if it was.
CREATE PROCEDURE FormAdd (p_formName varchar(500))
BEGIN
/* Attempt the insert, overwrite with the same value if necessary */
INSERT INTO tbl_Form (formName) VALUES (p_formName) ON DUPLICATE KEY UPDATE formName = p_formName;
/* Return the LAST_INSERT_ID() for a new row and -1 otherwise */
SELECT
CASE
WHEN ROW_COUNT() = 1 THEN LAST_INSERT_ID()
ELSE -1
END AS returnValue;
END

PostgreSQL UPSERT Trigger returning id

I've an UPSERT trigger on a table that may update instead of inserting while doing insert operation. I've function doing insert on that table and returning id However it doesn't return an id when it updates instead of inserting. I want to get the id in both cases.
Trigger Code
perform 1 from tera_subject
where id = new.subject_id and owner = new.user_id;
if found then
return null;
else
select id into vote_id from tera_votes where
user_id = new.user_id and
subject_id = new.subject_id;
if not found then
return new;
else
-- raise notice 'vote_id: % ; vote: %',vote_id,new.vote;
if(tg_op = 'INSERT') then
begin
-- raise notice 'redirecting to update';
update tera_votes
set vote=new.vote
WHERE id = vote_id;
end;
elsif(tg_op = 'UPDATE') then
-- raise notice 'in update';
return new;
end if;
-- raise notice 'end of trigger %',tg_op;
return null;
end if;
end if;
end;
I don't think you'll manage to have anything “returned” by the trigger.
What you're doing inside is:
running update based on your conditions;
suppressing the INSERT statement that fired the trigger.
This means, that INSERT is terminated in an easy way (without exception), but it also means that it's impossible to provide you any details, as trigger functions do not return any values.
If you need to have the ID of the UPSERT-ed item, consider using a function that will always return you the ID, like this one.