Using and UPDATE Trigger to Modify the Row Being Updated - sql-server-2008

I have an employee table (em) that contains, among other things, a floor Id (fl_id) and room Id (rm_id). In certain circumstances (when em_loc_cnt = 0) I want to set the em record's fl_id and rm_id to null. Below is my code so far.
I am not sure how to refer to the fl_id & rm_id in the commented line. Will I run into issues because this trigger is being called as a result of the em record being updated and I am updating that same record in the trigger?
Suggestions?
IF EXISTS (SELECT * FROM [sysobjects] WHERE [name] = 'em_upd_self_serv_t' AND [type] = 'TR')
BEGIN
DROP TRIGGER [dbo].[em_upd_self_serv_t]
END
GO
CREATE TRIGGER [dbo].[em_upd_self_serv_t]
ON [dbo].[em]
AFTER UPDATE
AS
BEGIN
DECLARE #em_id VARCHAR(35),
#em_loc_cnt INT;
SET #em_id = (SELECT em_id FROM inserted);
SET #em_loc_cnt = (SELECT COUNT(*) FROM emlocs WHERE em_id = #em_id);
IF (#em_loc_cnt = 0)
BEGIN
-- I want to set the fl_id and the rm_id to NULL
END
END;

Your fundamental flaw is that you seem to expect the trigger to be fired once per row - this is NOT the case in SQL Server. Instead, the trigger fires once per statement, and the pseudo table Inserted might contain multiple rows.
Given that that table might contain multiple rows - which one do you expect will be selected here??
SET #em_id = (SELECT em_id FROM inserted);
It's undefined - you might get the values from arbitrary rows in Inserted.
You need to rewrite your entire trigger with the knowledge the Inserted WILL contain multiple rows! You need to work with set-based operations - don't expect just a single row in Inserted !
You need to change your code to something like this:
IF EXISTS (SELECT * FROM sys.triggers WHERE [name] = 'em_upd_self_serv_t')
DROP TRIGGER [dbo].[em_upd_self_serv_t]
GO
CREATE TRIGGER [dbo].[em_upd_self_serv_t]
ON [dbo].[em]
AFTER UPDATE
AS
UPDATE dbo.em
SET fl_id = NULL, rm_id = NULL
FROM Inserted i
WHERE em_id = i.em_id
AND NOT EXISTS (SELECT * FROM dbo.emlocs WHERE em_id = i.em_id)

Related

MySQL trigger - how to update specific row in another table

I have these two tables
**Table tb_data**
tb_id
timestamp
pagid
proid
status
(and many more)
**Table tb_units**
pag_id
pag_sn
user
latest_profile
latest_status
latest_feedback
latest_timestamp
Whenever a new row is created in tb_data, i would like some values updated in tb_units. In tb_units pag_id is unique and every number only exists once.
How do I trigger this, so the new values in tb_data are updated in tb_units? pagid equals pag_id and the corresponding values proid should update latest_profil, status should update latest_status, timestamp should update latest_timestamp
In the end I would like to end up with the latest pagid input to tb_data to be available in tb_units, since tb_data will contain multiple rows from the same pagid
I hvae tried several different aproaches, and have read a lot of examples, but I just don't get how these triggers work!
Latest example, that doesn't work:
CREATE TRIGGER update_units
AFTER INSERT ON tb_data
BEGIN
UPDATE tb_units
SET latest_profile = tb_data.9C,
latest_status = tb_data.91
WHERE pag_id = tb_data.86;
END
Not sure but something like this should work
CREATE TRIGGER update_units
AFTER INSERT ON tb_data
BEGIN
UPDATE tb_units
SET latest_profile = new.proid,
latest_status = new.status
WHERE pag_id = new.pagid;
END

MySQL-Update inserted auto increment primary key to custom value

When I insert a new row, an auto increment ID will be saved like 1,2,3..
I need to custom it using a Trigger so it will be saved like 20171,20172,20173..
This trigger would do this.
CREATE DEFINER=`root`#`%` TRIGGER `test_before_insert` BEFORE INSERT ON `test` FOR EACH ROW BEGIN
SET NEW.id = (
SELECT CONCAT(YEAR(CURDATE()),IFNULL(MAX(CAST(ids.id AS UNSIGNED))+1,1))
FROM (
SELECT RIGHT(t.id,LENGTH(t.id)-4) AS id
FROM test t
WHERE LEFT(t.id,4) = YEAR(CURDATE())
) ids
);
END
But there are many reason you would not want to. This will get exponentially more expensive as rows are inserted, and provides no viable sorting etc.

Trigger returns results from all rows instead of one row

I'm trying to create a trigger on the employeepayhistory table. Whenever I update the RATE column in the table its effect on the monthly salary should be displayed, but instead it gives me the monthly salary of the whole record if I update one record. Please help.
CREATE TRIGGER MONTHTRG
ON HumanResources.EmployeePayHistory
FOR UPDATE
AS
BEGIN
DECLARE #Rate MONEY
SELECT #Rate=Rate FROM INSERTED
SELECT 'MONTHSAL'=Rate*PayFrequency*30 FROM HumanResources.EmployeePayHistory
END
You also need to give the where condition, typically you'll
DECLARE #Id bigint
SET #Id = (SELECT Id from Inserted)
SELECT 'MONTHSAL' = Rate * PayFrequency*30 From HumanResources.EmployeePayHistory where Humanresources.EmployeeID=#Id
This will work if the Primary key is called 'Id' and ofcourse, is unique. You can also do this with a Unique key(which should be Non-NULL)

creating triggers and functions in postgresql

how can i create a trigger function before adding/updating,the function should check records that have the same id (i.e comparison by id with existing objects that have the same property as the temporary_object)If a record with the id is found, then that entry is set to the time_dead, and then it adds an entry containing the corresponding values ​​of the attributes found in that record (except those that are set for a new record), when time_dead is empty then time_create of a new time is equal to that time at the current moment . Thus,a new record time_create is like the time_dead's ancestor.
If a record with that id is found then it is added to the database with the establishment as the time_create of the current time.
for example here is a simple explanation(just for explanation purposes)
id time_create time-dead student amount
1 06.12 07.12 henry 500
1 07.12 henry 1000
so if a student called henry with id 1 entered a room at 06.12 and left at 07.12 the next time he enters another room again time_dead will be equal to time_create(so time_dead of old entry and time_create of new entry - will be equal)
these are my tables below in sql format
CREATE TABLE temporary_object
(
id integer NOT NULL,
time_create timestamp without time zone NOT NULL,
time_dead timestamp without time zone,
CONSTRAINT temporary_object_pkey PRIMARY KEY (id, time_create)
)
CREATE TABLE persons
(
fname text,
fsurname text,
)
INHERITS (temporary_object)
CREATE TABLE rooms
(
roomnum integer,
course integer,
passport text,
students_number text
)
INHERITS (temporary_object)
this is what i am trying to do but im afraid i do not know how to finish it but im 100% not right may some help out
CREATE TRIGGER trigger2
BEFORE INSERT OR UPDATE
ON persons
FOR EACH ROW
EXECUTE PROCEDURE func1();
and this is the function
CREATE OR REPLACE FUNCTION func1() RETURNS TRIGGER AS $persons$
DECLARE
time_create integer;
time_dead timestamp;
id timestamp;
BEGIN
IF (TG_OP = 'INSERT') THEN
time_create=
I can't tell you what I'm missing from your question, but I try to answer what I think I understood.
Row level triggers can access the version of the row affected with the NEW and OLD variables (depending on TG_OP). In this case, you can use NEW:
CREATE OR REPLACE FUNCTION func1()
RETURNS TRIGGER AS
$persons$
DECLARE
i integer;
BEGIN
IF TG_OP = 'INSERT'
THEN
UPDATE persons
SET time_dead = NEW.time_create
WHERE
id = NEW.id -- we are looking for the same ID
AND time_dead IS NULL
;
ELSE -- UPDATE
-- do here something
END IF;
END;
$persons$
LANGUAGE plpgsql;
This is only a starter, modify it to your needs.

track multiple identical entries

I got a table that I am allowing identical entries (duplicates, triplecates etc.) but I also got a column that I want everytime that an entry is being made to be updated with the how many times that entry exists.
So I thought to write a trigger, I can already find the duplicate entries by doing
select count(pid) from items group by pid having count(*);
but the thing is that this query returns less columns that the orinal table (cause there are many duplicates)
so there is no 1 to 1 relation between the query and the table so I can use update. How could I modify this to get the desired result
thank you in advanced.
The main problem that you'll face here is that MySQL will not allow you to modify the items table using an AFTER INSERT ... trigger following a modification to the items table itself (think of how this could lead to a circular reference).
One solution is to store the counts in a separate table altogether (say items_pid_info). The primary key of this table would be pid and it is this table that would be updated by the triggers on the main items table. When you need to access the pidCount for a given pid simply join onto this table and you will have up-to-date pid counts for your given pid. Hence:
create table items_pid_info
(pid int unsigned not null primary key,
pidCount int unsigned not null);
Now create INSERT, UPDATE and DELETE triggers on your items table to update the items_pid_info table:
DELIMITER &&
CREATE TRIGGER items_pid_count_ins_trg
AFTER INSERT ON items
FOR EACH ROW BEGIN
DECLARE c int;
set c := (select count(*) from items im where im.pid = NEW.pid);
insert into items_pid_info values (NEW.pid,c) on duplicate key update pidCount = c;
END&&
CREATE TRIGGER items_pid_count_upd_trg
AFTER UPDATE ON items
FOR EACH ROW BEGIN
DECLARE c int;
set c := (select count(*) from items im where im.pid = NEW.pid);
insert into items_pid_info values (NEW.pid,c) on duplicate key update pidCount = c;
END&&
CREATE TRIGGER items_pid_count_del_trg
AFTER DELETE ON items
FOR EACH ROW BEGIN
DECLARE c int;
set c := (select count(*) from items im where im.pid = OLD.pid);
insert into items_pid_info values (OLD.pid,c) on duplicate key update pidCount = c;
END&&
DELIMITER ;
Hope this helps.