Is there a way to add insert/update/delete triggers in Clickhouse to keep track of changes in a specific table to write data that has been changed to another table.
Here is a similar script for Oracle:
CREATE OR REPLACE TRIGGER trigger_name
AFTER
INSERT OR UPDATE OR DELETE
ON table_name
FOR EACH ROW
DECLARE
action_type VARCHAR2(6);
BEGIN
action_type := CASE
WHEN INSERTING THEN 'insert'
WHEN UPDATING THEN 'update'
WHEN DELETING THEN 'delete'
END;
INSERT INTO ...
END;
Related
I developed a trigger to insert a history data for transaction table.
Create or replace trigger his_trg
After insert or update
On trans_tb
For each row
Declare
V_data number;
V_seq number := seq_name.nextval;
Begin
Select data into v_data from another_tb where key = :new.key;
If (inserting or updating) and nvl(:old.id) != (:New.id)
Insert into his_tb (column1, column2,column3,column4) Values (v_seq,v_data, :new.data1, :new.data2);
End if;
Exception
When others then
Dbms_output.put_line('error');
End;
Now issue is when i insert new record in trans_tb and update on newly inserted record means, records are inserted in his_tb.
But when i update already inserted record on trans_tb there will no insert happen in his_tb
Note: Am created trigger for trans_tb after 5 records are already created in trans_tb. And i made update on those 5 records will cause issue.
I would like to create a trigger that updates a field in a table after an update of a different field in the same table. I don't think this is possible with an 'after insert or update' trigger. It compiles but when I update the field it mutates.
I have created a 'before insert or update' trigger which works for inserts, but doesn't work for updates.
This is my code:
create or replace
trigger TRIGGER_1
after insert or update of TOTAL_COUNT on TABLE_1
for each row
when (new.TOTAL_COUNT = 0)
begin
update TABLE_1
set count_accuracy_cde = 'absent';
end;
create or replace
trigger TRIGGER_1
before insert or update on test_table
referencing new as new old as old
for each row
begin
if (:new.TOTAL_COUNT = 0) then
:new.count_accuracy_cde := 'absent';
end if;
end;
I need to restrict access to DDL with some table in oracle, forbid drop of the table. How I can do this? I just can create DDL trigger for database and schema
create table my_table(
id int primary key not null,
first_val int,
second_val int
);
create trigger delete_disabling_trigger
before drop on database
begin
if --some condition
dbms_output.put_line('delete_disabling_trigger');
RAISE_APPLICATION_ERROR(-175,'Cant delete this table');
end if;
end;
If you need table that someone won't be able to drop you can create the table in another schema. Give grants to select, insert, update, delete and create synonym for user that is using the table.
Scenario: User X needs table T which can't be dropped.
Create user persist identified by password.
Create table persist.T ...
GRANT SELECT, INSERT, UPDATE, DELETE on persist.T to X;
create synonym X.T for persist.T;
In such scenario X can manipulate data but can't change structure or drop table. Using trigger seems to be weird solution to block dropping table.
EDIT
create or replace trigger delete_disabling_trigger
before drop on database
begin
if(ORA_DICT_OBJ_NAME = 'MY_TABLE') then --and ORA_DICT_OBJ_OWNER = 'YOUR_SCHEMA'
dbms_output.put_line('delete_disabling_trigger');
RAISE_APPLICATION_ERROR(-20000,'Cant delete this table');
end if;
end;
/
I have just implemented a trigger to stop the drop of 5 tables which are being dropped from 2 development schemas by some as yet unknown process. We register the attempt in a table with an autonomous transaction, and stop the drop.
I hope to identify the process soon and get rid of the trigger.
CREATE OR REPLACE TRIGGER whos_dropping_my_table
BEFORE DROP
ON database
declare
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into some_table_I_prepared_earlier
VALUES( SUBSTR(ora_sysevent,1,50),
SUBSTR(ora_dict_obj_owner,1,50),
SUBSTR(ora_dict_obj_name,1,50),
SUBSTR(ora_dict_obj_TYPE,1,50),
UPPER(sys_context('USERENV','TERMINAL')),
SYSDATE,
UPPER(sys_context('USERENV','OS_USER'))
);
commit;
if SUBSTR(ora_dict_obj_name,1,50) in
('TABLE_1','TABLE_2','TABLE_3','TABLE_4','Table_5')
then
begin
RAISE_APPLICATION_ERROR(num => -20998,
msg => 'Stop deleting my table, whoever you are');
end;
end if;
end;
I am performing an archival process on a huge database and it involves deleting the production active table and renaming another table to be the new production table. When dropping the production active table, the triggers also get deleted. So I am just taking a backup of the triggers defined on my table using
select * from all_triggers where table_name=mytablename;
My question is, can I directly copy these triggers in to the all_triggers table after I rename my other table to be the new production active table? Will the triggers still work?
Same question for defining indexes and constraints too.
Copying the triggers from one table to another can be done by copying DDL, and not updating all_triggers table. This can be done by using DBMS_METADATA.
The closest practical example I found here: Copy Triggers when you Copy a Table
The following script can be amended as per your need:
declare
p_src_tbl varchar2(30):= 'PERSONS'; --your table name
p_trg_tbl varchar2(30):= 'PSN2'; --your trigger name
l_ddl varchar2(32000);
begin
execute immediate 'create table '||p_trg_tbl||' as select * from '||p_src_tbl||' where 1=2';
for trg in (select trigger_name from user_triggers where table_name = p_src_tbl) loop
l_ddl:= cast(replace(replace(dbms_metadata.get_ddl( 'TRIGGER', trg.trigger_name),p_src_tbl,p_trg_tbl),trg.trigger_name,substr(p_trg_tbl||trg.trigger_name, 1, 30)) as varchar2);
execute immediate substr(l_ddl, 1, instr(l_ddl,'ALTER TRIGGER')-1);
end loop;
end;
/
No, you cannot directly manipulate data dictionary tables. You can't insert data directly into all_triggers (the same goes for any data dictionary table). I guess you probably could given enough hacking. It just wouldn't work and would render your database unsupported.
The correct way to go is to script out your triggers and reapply them later. If you want to do this programmatically, you can use the dbms_metadata package. If you want to get the DDL for each of the triggers on a table, you can do something like
select dbms_metadata.get_ddl( 'TRIGGER', t.trigger_name, t.owner )
from all_triggers t
where table_owner = <<owner of table>>
and table_name = <<name of table>>
To replicate your scenario i have prepared below snippet. Let me know if this helps.
--Simple example to copy Trigger from one table to another
CREATE TABLE EMP_V1 AS
SELECT * FROM EMP;
--Creating Trigger on Old Table for Example purpose
CREATE OR REPLACE TRIGGER EMP_OLD_TRIGGER
AFTER INSERT OR UPDATE ON EMP FOR EACH ROW
DECLARE
LV_ERR_CODE_OUT NUMBER;
LV_ERR_MSG_OUT VARCHAR2(2000);
BEGIN
dbms_output.put_line('Your code for data Manipulations');
--Like Insert update or DELETE activities
END;
-- To replace this trigger for emp_v2 table
set serveroutput on;
DECLARE
lv_var LONG;
BEGIN
FOR i IN (
SELECT OWNER,TRIGGER_NAME,DBMS_METADATA.GET_DDL('TRIGGER','EMP_OLD_TRIGGER') ddl_script FROM all_triggers
WHERE OWNER = 'AVROY') LOOP
NULL;
lv_var:=REPLACE(i.ddl_script,'ON EMP FOR EACH ROW','ON EMP_V1 FOR EACH ROW');
dbms_output.put_line(substr(lv_var,1,INSTR(lv_var,'ALTER TRIGGER',1)-1));
EXECUTE IMMEDIATE 'DROP TRIGGER '||I.TRIGGER_NAME;
EXECUTE IMMEDIATE lv_var;
END LOOP;
END;
--Check if DDL manipulation has been done for not
SELECT OWNER,TRIGGER_NAME,DBMS_METADATA.GET_DDL('TRIGGER','EMP_OLD_TRIGGER') ddl_script FROM all_triggers
WHERE OWNER = 'AVROY';
---------------------------------OUTPUT----------------------------------------
"
CREATE OR REPLACE TRIGGER "AVROY"."EMP_OLD_TRIGGER"
AFTER INSERT OR UPDATE ON EMP_V1 FOR EACH ROW
DECLARE
LV_ERR_CODE_OUT NUMBER;
LV_ERR_MSG_OUT VARCHAR2(2000);
BEGIN
dbms_output.put_line('Your code for data Manipulations');
--Like Insert update or DELETE activities
END;
"
-----------------------------OUTPUT----------------------------------------------
I'm trying to build a trigger which takes the specific updated row and insert it into another table, but I'm not able to build it.
This is what I was able to build:
CREATE OD REPLACE TRIGGER Z_ONUPDATELOGIN
AFTER UPDATE OF LAST_LOGGED_IN_DATE ON CMN_SEC_USERS csu
BEGIN
INSERT INTO Z_LOGIN (name, login_date)
select first_name||last_name,
last_logged_in_date
from cmn_sec_users usr
where usr.id=csu.id;
END;
When you deal with triggers you can use the :NEW and :OLD keyword to work with the new and old values of the row you are modifying. In your case try this:
CREATE OR REPLACE TRIGGER Z_ONUPDATELOGIN
AFTER UPDATE OF LAST_LOGGED_IN_DATE ON CMN_SEC_USERS
FOR EACH ROW
BEGIN
INSERT INTO Z_LOGIN (name, login_date)
VALUES (:NEW.first_name || :NEW.last_name,
:NEW.last_logged_in_date);
END;