SQL Triggers in Oracle - sql

My question is as follows:
User name = Admin
Whenever I perform an insert/update/delete operation on a table "a". I need to have a trigger that would insert the username in table "b"
Is that possible?

create or replace trigger audit_a_trg
before insert or update or delete on A
for each row
begin
insert into b values (user);
end;
/
Oracle's online documentation is pretty good. You can read the SQL reference here.
edit
user is a function which returns the name of the account which issues the DML. Find out more.

Related

Trigger for creating a new record after new user creation doesn't work in PostgreSQL

I have a settings table and a users table. I want to create a trigger to insert a new settings record every time a new user gets created and reference the id of the newly created user in the settings record(settings.user_id in this case). Currently, I've come up with this trigger and function but whenever I try to insert a record into the users table the query fails to execute.
Procedure:
CREATE OR REPLACE FUNCTION create_settings()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
INSERT INTO settings (user_id) VALUES (OLD.id);
RETURN OLD;
END;
$$
Trigger:
CREATE TRIGGER create_settings
AFTER INSERT ON users
EXECUTE PROCEDURE create_settings();
and here's the error I get:
ERROR: null value in column "user_id" of relation "settings" violates not-null constraint
DETAIL: Failing row contains (95a8d1ae-cf9d-40be-b5d2-b2d231fb7e1b, null, null, null, null, light, 2022-01-02 15:29:14.290823).
CONTEXT: SQL statement "INSERT INTO settings (user_id) VALUES (OLD.id)"
PL/pgSQL function create_settings() line 3 at SQL statement
The only field that I need is the first null from the error which is the actual reference to the user by ID(most of the values that are null are optional and are NULL by default).
Take a look at the documentation for create trigger. In particular the difference between row level and statement level triggers. You save a statement level trigger. Statement level triggers do not have the pseudo roes Old or New values, They are all null. You need a row level trigger to get values from Old or New. So:
CREATE TRIGGER create_settings
AFTER INSERT ON users
for each row
EXECUTE PROCEDURE create_settings();
It is important to notice that the OLD variable is only available for triggers that execute UPDATE/DELETE in row-level as shown here, so in this case is not possible to get the data you want with an INSERT trigger.

Oracle Trigger with INSERT INTO table

I am trying to create an Oracle Trigger with After Update statement. It appears that I cannot create the trigger because I get prompted with Table does not exist error:
CREATE OR REPLACE TRIGGER USR1.CORE_FINISHED
AFTER UPDATE OF RUNTIME_STATUS
ON USR2.runtime_btc
FOR EACH ROW
WHEN ( new.RUNTIME_STATUS = 'FINISHED'
AND new.id = 'cr_daily')
BEGIN
INSERT INTO USR1.test_dq_log (BTC_NO, TBL_NAM, SCR_NAM)
SELECT BTC_NO, TBL_NAM, SCR_NAM
FROM USR2.EVENT_LG -- This is where the script is throwing errors
WHERE BTC_NO = :NEW.BTC_NO;
END;
What is weird is that the same expression when run outside of the trigger:
INSERT INTO USR1.test_dq_log (BTC_NO, TBL_NAM, SCR_NAM)
SELECT BTC_NO, TBL_NAM, SCR_NAM
FROM USR2.EVENT_LG
WHERE BTC_NO = 'any number here'
Seems to work smoothly and it inserts rows in the table!
It looks as if you were granted privileges to insert into that table via role. Were you?
If so, it works at SQL level or anonymous PL/SQL blocks, but won't work in named PL/SQL procedures (e.g. stored procedures, functions, triggers) - you'll have to acquire that grant directly (not via role).

trigger to update specific column when insert/update happened in same table

I trying to write a trigger that will update a column when user insert or updates a row, within the same table.
Example:
insert into user(ID, F_NM, L_NM, EMAIL) values ('1', 'John','Doe','john.doe#market.org.com');
after the insert, i want to call: update user set ORG = 'market' where ID = '1'.
create or replace trigger user_change
after insert or update of EMAIL on USER
for each row
declare
NEW_ORG VARCHAR(10);
BEGIN
CASE
when :NEW.EMAIL like '$#market.org.com' then
NEW_ORG := 'market';
........
END CASE;
UPDATE USER set ORG = NEW_ORG where ID = :NEW.ID
END;
Calculating the new ORG work, but I can't get the update statement to work.
I get 'ORA-04091 table USER is mutating, trigger/funtion may not see it', figure its due to me inserting/updating the same record at same time. Tried adding 'pragma autonomous_transaction' and 'commit' to the trigger, the insert/update of fields works but the ORG does not get updated.
Also tried changing to INSTEAD OF INSERT OR UPDATE OF EMAIL but I keep getting 'ORA-04073 column list not valid for this trigger type'
create or replace trigger user_change
instead of insert or update of EMAIL on USER
while i get 'ORA-25002 cannot create instead of triggers on tables'
create or replace trigger user_change
instead of insert on USER
Why not simply turn the trigger to a before trigger, when you can set the value before it is written? This way, you don't need to run a new DML statement on the table, which avoid the "mutating" error.
create or replace trigger user_change
after insert or update of email on user
for each row
begin
if :new.email like '%#market.org.com' then
:new.org := 'market';
end if;
end;
Looks like your org column can be calculated virtual column. In this case it would be better to create user-defined deterministic pl/sql function that returns correct calculated value and add it to your table, for example:
Alter table t add org varchar2(30) generated always as (f_get_org(email))

PostgreSQL FOUND for CREATE TABLE statements

I am creating a function that will create a new table and insert informations about that table into other tables.
To create that table I am using the
CREATE TABLE IF NOT EXISTS
statement. Sadly it does not update the FOUND special variable in PostgreSQL nor can i find any other variable that would be updated.
Is there any way in PL/PGSQL to know whether that statement created a table or not?
The target of it is to not to double the informations in the other tables.
You may use CREATE TABLE AS in combination with ON_ERROR_ROLLBACK:
BEGIN;
-- Do inital stuff
\set ON_ERROR_ROLLBACK on
CREATE TABLE my_table AS
SELECT id, name FROM (VALUES (1, 'Bob'), (2, 'Mary')) v(id, name);
\set ON_ERROR_ROLLBACK off
-- Do remaining stuff
END;
To put it bluntly, with \set ON_ERROR_ROLLBACK on postgres will create a savepoint before each statement and automatically rollback to this savepoint or releasing it depending on the success of that statement.
The code above will execute initial and remaining stuff even if the table creation fails.
No, there are not any information if this command created table or not. The found variable is updated after query execution - not after DDL command. There is guaranteed so after this command, the table will be or this command fails to an exception.

HANA: SQL Trigger to set a row's last modified date?

So, I understand how to create a trigger in HANA, but the examples in the HANA reference material do not mention how a trigger on Table A can update Table A; instead the material is always trigger on A updates B like the following example from the SAP docs:
CREATE TRIGGER TEST_TRIGGER_VAR_UPDATE
AFTER UPDATE ON TARGET
REFERENCING NEW ROW mynewrow, OLD ROW myoldrow
FOR EACH ROW
BEGIN
INSERT INTO SAMPLE_new VALUES(:mynewrow.a, :mynewrow.b);
INSERT INTO SAMPLE_old VALUES(:myoldrow.a, :myoldrow.b);
INSERT INTO SAMPLE VALUES(0, 'trigger');
END;
What's the preferred way of updating a column such as a LastModifiedDate? Would I set :mynewrow.LastModifiedDate = NOW(), or should I perform an UPDATE where the ID matches the ID of mynewrow?
As of SPS8, a HANA SQL Trigger can only perform INSERT, UPDATE, and DELETE statements against other tables. If you try to create a self-referencing Trigger, you'll find the following error message:
Modification of subject table in trigger not allowed