Create Trigger that Insert data after update on specific column - triggers

So i want to insert data to history_rent table and delete data in rent table after update status_peminjaman column on rent table, i am already create Trigger but it doesn't triggered
CREATE OR ALTER TRIGGER AfterUpdateStatus on dbo.peminjaman
FOR UPDATE
AS DECLARE
#nama_peminjam varchar(100),
#tanggal_pinjam datetime,
#tanggal_kemblali datetime,
#nama_guru varchar(100),
#status_peminjaman varchar(50),
#kode_barang varchar(255);
SELECT #nama_peminjam = ins.nama_peminjam FROM INSERTED ins;
SELECT #tanggal_pinjam = ins.tanggal_pinjam FROM INSERTED ins;
SELECT #tanggal_kembali = ins.tanggal_kembali FROM INSERTED ins;
SELECT #nama_guru = ins.nama_guru FROM INSERTED ins;
SELECT #kode_barang = ins.kode_barang FROM INSERTED ins;
SELECT #status_peminjaman = ins.status_peminjaman FROM INSERTED ins;
IF UPDATE(status_peminjaman)
BEGIN
SET #status_peminjaman = 'Selesai'
END
INSERT INTO dbo.history_peminjaman
VALUES(#nama_peminjam,#tanggal_pinjam,#tanggal_kembali,#nama_guru,#kode_barang,#status_peminjaman);
PRINT 'TRIGEREDDDDDDDDD'
GO

Related

Create trigger to only populate history table if record doesnt exist

Need some help.
I need to update a trigger that already exists that when a new record is updated, the previous record is inserted in an history table.
Current trigger:
create or replace TRIGGER "AUDIT"
BEFORE UPDATE OF STATUS,UPDATE_DATE,CREATED_DATE,PREMISES_ID ON "PREMISES"
REFERENCING OLD AS OLD_PREMISES NEW AS NEW_PREMISES
FOR EACH ROW
BEGIN
INSERT INTO PREMISES_H
(
ID,
PREMISES_ID,
STATUS,
UPDATE_DATE,
CREATED_DATE
)
VALUES (
EDB_PREMISES_HISTORY_SEQ.nextval,
:OLD_PREMISES.PREMISES_ID,
:OLD_PREMISES.STATUS,
:OLD_PREMISES.UPDATE_DATE,
:OLD_PREMISES.CREATED_DATE
);
END;
Before inserting into PREMISES_H I need it to check if it already exists if it does just updates the UPDATE_DATE
create or replace TRIGGER "AUDIT"
BEFORE UPDATE OF STATUS,LAST_UPDATE_DATE,CREATED_DATE,PREMISES_ID ON "PREMISES"
REFERENCING OLD AS OLD_PREMISES NEW AS NEW_PREMISES
FOR EACH ROW
BEGIN
IF EXISTS (SELECT * FROM PREMISES_H WHERE PREMISES_ID = :OLD_PREMISES.PREMISES_ID AND STATUS = :OLD_PREMISES.STATUS)
THEN UPDATE PREMISES_H SET UPDATE_DATE = :OLD_PREMISES.UPDATE_DATE WHERE PREMISES_ID = :OLD_PREMISES.PREMISES_ID AND ELIGIBILITY_STATUS = :OLD_PREMISES.STATUS;
ELSE INSERT INTO PREMISES_H
(
ID,
PREMISES_ID,
STATUS,
LAST_UPDATE_DATE,
CREATED_DATE
)
VALUES (
EDB_PREMISES_HISTORY_SEQ.nextval,
:OLD_PREMISES.PREMISES_ID,
:OLD_PREMISES.STATUS,
:OLD_PREMISES.LAST_UPDATE_DATE,
:OLD_PREMISES.CREATED_DATE
);
END;
Would this be the best approach?
Thank you
I was expecting to no insert if the record from premises already exists in premises_h

Copying records in a table with self referencing ids

I have a table with records which can reference another row in the same table so there is a parent-child relationship between rows in the same table.
What I am trying to achieve is to create the same data for another user so that they can see and manage their own version of this structure through the web ui where these rows are displayed as a tree.
Problem is when I bulk insert this data by only changing user_id, I lose the relation between rows because the parent_id values will be invalid for these new records and they should be updated as well with the newly generated ids.
Here is what I tried: (did not work)
Iterate over main_table
copy-paste the static values after each
do another insert on a temp table for holding old and new ids
update old parent_ids with new ids after loop ends
My attempt at doing such thing(last step is not included here)
create or replace function test_x()
returns void as
$BODY$
declare
r RECORD;
userId int8;
rowPK int8;
begin
userId := (select 1)
create table if not exists id_map (old_id int8, new_id int8);
create table if not exists temp_table as select * from main_table;
for r in select * from temp_table
loop
rowPK := insert into main_table(id, user_id, code, description, parent_id)
values(nextval('hibernate_sequence'), userId, r.code, r.description, r.parent_id) returning id;
insert into id_map (old_id, new_id) values (r.id, rowPK);
end loop;
end
$BODY$
language plpgsql;
My PostgreSQL version is 9.6.14.
DDL below for testing.
create table main_table(
id bigserial not null,
user_id int8 not null,
code varchar(3) not null,
description varchar(100) not null,
parent_id int8 null,
constraint mycompkey unique (user_id, code, parent_id),
constraint mypk primary key (id),
constraint myfk foreign key (parent_id) references main_table(id)
);
insert into main_table (id, user_id, code, description, parent_id)
values(0, 0, '01', 'Root row', null);
insert into main_table (id, user_id, code, description, parent_id)
values(1, 0, '001', 'Child row 1', 0);
insert into main_table (id, user_id, code, description, parent_id)
values(2, 0, '002', 'Child row 2', 0);
insert into main_table (id, user_id, code, description, parent_id)
values(3, 0, '002', 'Grand child row 1', 2);
How to write a procedure to accomplish this?
Thanks in advance.
It appears your task is coping all data for a given user to another while maintaining the hierarchical relationship within the new rows. The following accomplishes that.
It begins creating a new copy of the existing rows with the new user_id, including the old row parent_id. That will be user in the next (update) step.
The CTE logically begins with the new rows which have parent_id and joins to the old parent row. From here it joins to the old parent row to the new parent row using the code and description. At that point we have the new id along with the new parent is. At that point just update with those values. Actually for the update the CTE need only select those two columns, but I've left the intermediate columns so you trace through if you wish.
create or replace function copy_user_data_to_user(
source_user_id bigint
, target_user_id bigint
)
returns void
language plpgsql
as $$
begin
insert into main_table ( user_id,code, description, parent_id )
select target_user_id, code, description, parent_id
from main_table
where user_id = source_user_id ;
with n_list as
(select mt.id, mt.code, mt.description, mt.parent_id
, mtp.id p_id,mtp.code p_code,mtp.description p_des
, mtc.id c_id, mtc.code c_code, mtc.description c_description
from main_table mt
join main_table mtp on mtp.id = mt.parent_id
join main_table mtc on ( mtc.user_id = target_user_id
and mtc.code = mtp.code
and mtc.description = mtp.description
)
where mt.parent_id is not null
and mt.user_id = target_user_id
)
update main_table mt
set parent_id = n_list.c_id
from n_list
where mt.id = n_list.id;
return;
end ;
$$;
-- test
select * from copy_user_data_to_user(0,1);
select * from main_table;
CREATE TABLE 'table name you want to create' SELECT * FROM myset
but new table and myset column name should be equal and you can also
use inplace of * to column name but column name exist in new table
othwerwise getting errors

Trigger not saving historicals

Version: SQL Server 2008 R2
This trigger checks primary key violations, if any moves the row to the history table; and then deletes the row; and then inserts the row that caused the violation.
But it is not doing its job.
CREATE TRIGGER [dbo].[ONINSERT]
ON [dbo].[TICKETS]
Instead of INSERT
AS
BEGIN
DECLARE #ID VARCHAR(200)
SET NOCOUNT ON;
SET #ID = (SELECT TICKET_ID FROM inserted)
INSERT TICKET_HISTORY
SELECT * FROM TICKETS
WHERE
TICKET_ID = #ID ;
print 'Inserting ' + #id
DELETE FROM TICKETS
WHERE TICKET_ID = #ID;
print 'Deleting' + #id
INSERT TICKETS
SELECT * FROM inserted;
print 'Inserting back' + #id
Triggers fire only once even if you have multiple inserts,so in your case I don't see that happening...You don't need to delete the row again since instead of insert generally means "instead of insert do some custom action"
if exists
(
select 1 from inserted i
join
mytable t
on t.id=i.id
)
begin
--insert into tickets history
insert into ticketshistory
select i.* from inserted i
join
mytable t where t.id=i.id
---you can add custom logic to alert or simply ignore
return
end
--this is needed since if there is no violation you have to insert rows
insert into tickets
select * from inserted

Functions and Triggers in PostgreSql

As I am new to DBs, I am learning PostgreSql and for a sample, I am trying to small scenario on Mobile Recharge Database System. The below is the query I have. I want to know what is the problem with the function I have written which should only return balance amount of an account number which is nothing but the customer id.
And, I also want to add the value in the wallet table when we add some value (that's topup kind of).
Please help me in this. Thanks.
The below is the complete query:
CREATE DATABASE "RECHARGESYS"
WITH OWNER = postgres
ENCODING = 'UTF8'
TABLESPACE = pg_default
LC_COLLATE = 'English_United States.1252'
LC_CTYPE = 'English_United States.1252'
CONNECTION LIMIT = -1;
--SERVICEPROVIDER TABLE:
DROP TABLE SERVICE_PROVIDERS;
CREATE TABLE SERVICE_PROVIDERS
(
SPID VARCHAR(5) PRIMARY KEY CHECK(SPID LIKE 'S%'),
SPNAME VARCHAR(50)
);
--CUSTOMER TABLE:
DROP TABLE CUSTOMER;
CREATE TABLE CUSTOMER
(
CID INT PRIMARY KEY,
CNAME VARCHAR(50)
);
--RECHARGE TABLE:
DROP TABLE RECHARGE;
CREATE TABLE RECHARGE
(
RID INT PRIMARY KEY,
CID INT REFERENCES CUSTOMER(CID),
SPID VARCHAR(5) REFERENCES SERVICE_PROVIDERS(SPID) CHECK(SPID LIKE 'S%'),
RENUMBER BIGINT,
AMOUNT INT
);
--TRANSACTION TABLE:
DROP TABLE TRANSACTION;
CREATE TABLE TRANSACTION
(
TID INT PRIMARY KEY,
SPID VARCHAR(5) REFERENCES SERVICE_PROVIDERS(SPID) CHECK(SPID LIKE('S%')),
RID INT REFERENCES RECHARGE(RID)
);
--WALLET TABLE:
DROP TABLE WALLET;
CREATE TABLE WALLET
(
WID INT PRIMARY KEY,
CID INT REFERENCES CUSTOMER(CID),
WAMOUNT INT
);
INSERT INTO SERVICE_PROVIDERS VALUES ('S1001', 'AIRTEL');
INSERT INTO SERVICE_PROVIDERS VALUES ('S1002', 'AIRCEL');
INSERT INTO SERVICE_PROVIDERS VALUES ('S1003', 'TATA DOCOMO');
INSERT INTO SERVICE_PROVIDERS VALUES ('S1004', 'IDEA');
INSERT INTO SERVICE_PROVIDERS VALUES ('S1005', 'VODAFONE');
SELECT * FROM SERVICE_PROVIDERS;
INSERT INTO CUSTOMER VALUES('20001','AHMED');
INSERT INTO CUSTOMER VALUES('20002','ASIF');
INSERT INTO CUSTOMER VALUES('20003','AHSRAF');
INSERT INTO CUSTOMER VALUES('20004','MAHESH');
INSERT INTO CUSTOMER VALUES('20005','ARUN');
SELECT * FROM CUSTOMER;
INSERT INTO WALLET VALUES('30001','20001','1000');
INSERT INTO WALLET VALUES('30002','20002','1000');
INSERT INTO WALLET VALUES('30003','20003','1000');
INSERT INTO WALLET VALUES('30004','20004','1000');
INSERT INTO WALLET VALUES('30005','20005','1000');
SELECT * FROM WALLET;
--IN THIS FUNCTION I WANT TO CHECK THE BALANCE ONCE I GIVE THE ACCOUNT NUMBER / CUSTOMER ID (ID):
CREATE OR REPLACE FUNCTION BALANCE(ACCNO INT)
RETURNS INT AS $BAL$
BEGIN
SELECT WAMOUNT INTO BAL FROM WALLET WHERE CID=ACCNO;
RETURN(BAL);
END;
$BAL$ LANGUAGE plpgsql;
SELECT BALANCE('20001') FROM WALLET;
--ALSO I WANT TRIGGER THAT CAN ADD AMOUNT TO THE WALLET.
The problem with your function is that you try to use the variable BAL without declaring it:
CREATE OR REPLACE FUNCTION BALANCE(ACCNO INT)
RETURNS INT AS $BAL$
declare BAL integer; --<--- Add this line
.......
But for a simple select query you don't need a plpgsql function. A sql function will do the job:
CREATE OR REPLACE FUNCTION balance(ACCNO INT)
RETURNS INT AS $$
SELECT wamount FROM wallet WHERE cid=ACCNO;
$$ LANGUAGE sql;

Update column of a inserted row with with its generated id in a single query

Say I have a table, created as follows:
CREATE TABLE test_table (id serial, unique_id varchar(50) primary key, name varchar(50));
test_table
----------
id | unique_id | name
In that table, I would like to update the unique_id field with the newly inserted id concatenated with the inserted name in a single go.
Usually this is accomplished by two queries. (PHP way)
$q = "INSERT INTO table (unique_id,name) values ('uid','abc') returning id||name as unique_id;";
$r = pg_query($dbconn,$q);
$row = pg_fetch_array($r);
$q1 = "UPDATE test_table set unique_id =".$row['unique_id']." where unique_id='uid'";
$r1 = pg_query($dbconn,$q1);
Is there any way to do the above in a single query?
You can have several options here, you could create a AFTER trigger which uses the generated ID for an direct update of the same row:
CREATE TRIGGER test_table_insert ON AFTER INSERT ON test_table FOR EACH ROW EXECUTE PROCEDURE test_table_insert();
And in your function you update the value:
CREATE FUNCTION test_table_insert() RETURNS TRIGGER AS $$
BEGIN
UPDATE test_table SET uniqid = NEW.id::text || NEW.name WHERE id = NEW.id;
END;
$$ LANGUAGE plpgsql;
You need to add the function before the trigger.
An other option would be to do it directly in the insert:
INSERT INTO table (id, unique_id, name) values (nextval('test_table_id_seq'), 'abc', currval('test_table_id_seq')::text || 'abc') returning id;
But as a_horse_with_no_name pointed out, I think you may have a problem in your database design.