I am trying to set age = 0 if the age is inserted as negative. I don't know what is wrong with the code:
CREATE TRIGGER verify_age
BEFORE INSERT ON customers
FOR EACH ROW
WHEN (NEW.age < 0)
BEGIN
UPDATE customers
SET age = 0
END;
The syntactical error in your code is that it is missing a ; before END, but even if you correct this it would not solve your problem.
You need a WHERE clause in the UPDATE statement so that you update only the new row and not the whole table.
The condition in the WHERE clause will check for the rowid of the new row, but this rowid exists only after the row is inserted.
So, you must change the trigger to an AFTER INSERT trigger:
CREATE TRIGGER verify_age AFTER INSERT ON customers
WHEN NEW.age < 0
BEGIN
UPDATE customers
SET age = 0
WHERE rowid = NEW.rowid;
END;
See the demo.
Try this:
CREATE OR REPLACE TRIGGER validate_age
BEFORE INSERT
ON customers
FOR EACH ROW
BEGIN
IF :new.age < 0
THEN
:new.age := 0;
END IF;
END;
or :
CREATE TRIGGER validate_age
BEFORE INSERT ON customers
BEGIN
SELECT
CASE
WHEN NEW.age < 0 THEN
NEW.age = 0
END;
END;
Related
I am trying to create a trigger that after INSERT OR UPDATE OF columnX OR DELETE ON tableA
will increment or decrement by 1 columnY in tableB where tableB.key = tableA.key
For example: table product(droduct_id,product_rating) and table sale_line(sale_id, product_id,sale_qty)
Every time a greater quantity is entered into sale_line.sale_qty, product.product_rating is incremented by 1 and vice versa.
Thus, the greater is the quantity of a product in the sale_qty in the sale_line table, the greater is its rating in the product table
I have tried few variants found in different posts but none of them worked.
If I manage incrementing o decrementing the rating column, it goes for the whole table and not for the specific row.
How can I specify that changes in one table trigger changes in another table and all that happens for a certain product?
Now I know that the problem is my insufficient knowledge and some guys expressed the opinion that a trigger is the last thing to have, but this is why I want to understand it.
For the moment, this is what I have and it throws this error:
ORA-04079: invalid trigger specification
CREATE OR REPLACE TRIGGER t
AFTER INSERT OR UPDATE OF columnX OR DELETE
ON tableA
BEGIN
IF INSERTING AND :NEW.columnX > 2 THEN
UPDATE tableB
SET columnY = columnY + 1
WHERE columnY = 0;
ELSIF UPDATING AND :NEW.columnX < :OLD.columnX THEN
UPDATE tableB
SET columnY = columnY - 1
WHERE columnY <> 0;
ELSIF DELETING THEN
UPDATE tableB
SET columnY = 0
WHERE columnY <> 0;
END IF;
END;
Try it like this:
create or replace TRIGGER trg_aft_ins_upd_del_a_tbl
AFTER INSERT OR UPDATE OF COL_X OR DELETE
ON A_TBL
FOR EACH ROW
DECLARE
cnt NUMBER;
BEGIN
IF INSERTING AND :new.COL_X > 2 THEN
-- update if exist a row in B_TBL with ID = inserted ID - else insert new row in B_TBL
Select Count(*) INTO cnt From B_TBL Where ID = :new.ID;
IF cnt > 0 THEN
UPDATE B_TBL
SET COL_Y = COL_Y + 1
WHERE ID = :new.ID;
ELSE
INSERT INTO B_TBL (ID, COL_Y) VALUES(:new.ID, 1);
END IF;
-- if update decreased the value
ELSIF UPDATING AND :new.COL_X < :old.COL_X THEN
UPDATE B_TBL
SET COL_Y = COL_Y - 1
WHERE ID = :new.ID;
-- if update increased the value
ELSIF UPDATING AND :new.COL_X > :old.COL_X THEN
UPDATE B_TBL
SET COL_Y = COL_Y + 1
WHERE ID = :new.ID;
-- on delete set to 0
ELSIF DELETING THEN
UPDATE B_TBL
SET COL_Y = 0
WHERE ID = :old.ID;
END IF;
END;
If an entire row of null values is inserted into my table, I am wanting to execute a trigger to change all columns the newly inserted row to the average instead of null.
I have created the trigger function:
create or replace function teammate_null_check()
returns trigger as
$$
begin
if new.score is null then new.score = (select avg(score) from doubles.teammate);
elsif new.goals is null then new.goals = (select avg(goals) from doubles.teammate);
elsif new.assists is null then new.assists = (select avg(assists) from doubles.teammate);
elsif new.saves is null then new.saves = (select avg(saves) from doubles.teammate);
elsif new.shots is null then new.shots = (select avg(shots) from doubles.teammate);
end if;
return new;
end;
$$ language plpgsql
And the trigger event:
create trigger teammate_trigger
before insert on doubles.teammate
for each row
execute procedure teammate_null_check()
However when I insert a null value for all columns on my table, the trigger only sets the first column (score) to the average. I've tried using ifelse and a case statement and they both only update the first column.
This is what the table looks like after insert:
score
goals
assist
saves
shots
1234
1
2
3
4
1234
null
null
null
null
How can I update all columns if the entire row is inserted null?
ELsif for the alghorithm to choose only one column, but if ypu want all columns t be checked, you need to check eac column individually
create or replace function teammate_null_check()
returns trigger as
$$
begin
if new.score is null then
new.score = (select avg(score) from doubles.teammate);
end if;
if new.goals is null then new.goals = (select avg(goals) from doubles.teammate); end if;
if new.assists is null then new.assists = (select avg(assists) from doubles.teammate); end if;
if new.saves is null then new.saves = (select avg(saves) from doubles.teammate); end if;
if new.shots is null then new.shots = (select avg(shots) from doubles.teammate);
end if;
return new;
end;
$$ language plpgsql
I want to create trigger but I don't know how to do that. Below is the sample:
CREATE OR REPLACE TRIGGER checkDuration
after UPDATE on comm_shipping
FOR EACH ROW
DECLARE
quantity NUMBER;
BEGIN
SELECT * FROM comm_orders c
WHERE C.ORDER_ID = :new.order_id
AND c.quantity = 1;
IF quantity=NULL THEN
RAISE_APPLICATION_ERROR('no more items');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
Try the following ( I suppose your DBMS is Oracle or DB2 because of RAISE_APPLICATION_ERROR ):
CREATE OR REPLACE TRIGGER checkDuration
AFTER UPDATE ON comm_shipping
FOR EACH ROW
DECLARE
quantity NUMBER;
BEGIN
SELECT c.quantity
INTO quantity -- this part is missing
FROM comm_orders c
WHERE c.order_id = :new.order_id;
IF quantity is NULL THEN
RAISE_APPLICATION_ERROR(-20001,'no more items'); -- you need a code
-- between -20000 and -20999
END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
I am trying to write trigger which will control if a record is already in table or not. If is the record already in table (compare for example by name), so current record set valid='False' and insert new. Is there any way?
This is my idea, but it doesn't work.
create or replace TRIGGER
Check_r
before insert on t$customer
FOR each ROW
declare
v_dup number;
v_com number;
v_id number;
v_id_new number;
begin
v_date:=SYSDATE;
select count(id) INTO v_dup from t$customer where surname=:NEW.surname ;
select count(id) INTO v_com from t$customer where firstname =:NEW.firstname and
address=:NEW.address;
select id into v_id from t$customer where surname=:NEW.surname;
if v_dup > 0 and v_com=0 then
v_id_new:= m$_GET_ID; -- get id
update t$customer set valid = 'False' where id = v_id;
insert into t$customer ( id, surname ,firstname, valid, address ) values (v_id_new,:NEW.surname ,:NEW.firstname, :NEW.valid, :NEW.address);
end if;
if v_dup = 0 then
v_id_new:= m$_GET_ID; -- get id
insert into t$customer ( id, surname ,firstname, valid , address) values (v_id_new,:NEW.surname ,:NEW.firstname, :NEW.valid, :NEW.address);
end if;
end;
You can use a compound trigger, for example:
CREATE OR REPLACE TRIGGER Check_r
FOR INSERT ON t$customer
COMPOUND TRIGGER
TYPE customerRecordType IS RECORD(
surname t$customer.surname%TYPE,
firstname t$customer.firstname%TYPE,
address t$customer.address%TYPE,
ID nubmer);
TYPE customerTableType IS TABLE OF customerRecordType;
customerTable customerTableType := customerTableType();
n NUMBER;
BEFORE STATEMENT IS
BEGIN
customerTable.DELETE; -- not requried, just for better understanding
END STATEMENT;
BEFORE EACH ROW IS
BEGIN
customerTable.EXTEND;
customerTable(customerTable.LAST).surname := :NEW.surname;
customerTable(customerTable.LAST).firstname := :NEW.firstname;
customerTable(customerTable.LAST).address := :NEW.address;
customerTable(customerTable.LAST).ID := m$_GET_ID;
:NEW.ID := customerTable(customerTable.LAST).ID;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
FOR i IN customerTable.FIRST..customerTable.LAST LOOP
SELECT COUNT(*) INTO n
FROM t$customer
WHERE surname = customerTable(i).surname;
IF n > 1 THEN
UPDATE t$customer
SET valid = 'False'
WHERE surname = customerTable(i).surname;
END IF;
SELECT COUNT(*) INTO n
FROM t$customer
WHERE firstname = customerTable(i).firstname
AND address = customerTable(i).address;
IF n > 1 THEN
UPDATE t$customer
SET valid = 'False'
WHERE firstname = customerTable(i).firstname
AND address = customerTable(i).address
END IF;
END LOOP;
END AFTER STATEMENT;
END;
/
Please note, this solution is ugly and poor in terms of performance!
But it should give you an impression how it works.
In general you should put all this into a PL/SQL Procedure instead of a trigger.
First, this is trigger for insert. you don't need to write insert statement.
Second, you need to update old record. Just update it with your where clause.
CREATE OR REPLACE TRIGGER Check_r
before insert on t$customer
FOR each ROW
BEGIN
UPDATE t$customer set valid = 'False'
WHERE surname = :NEW.surname
AND firstname =:NEW.firstname;
:NEW.id := m$_GET_ID;
END;
I have the trigger
CREATE OR REPLACE TRIGGER my_trigger
AFTERE DELETE OR INSERT OR UPDATE ON my_table
FOR EACH ROW
DECLARE
V_PROJECT_ID VARCHAR2(10);
BEGIN
SELECT PJ_ID INTO V_PROJECT_ID FROM PROJECT_ROLES_GROUPS
WHERE GRP_ID = :OLD.GRP_ID;
UPDATE PROJECTS SET TOCUHED = 1 WHERE ID = V_PROJECT_ID;
END;
but the select statement inside the trigger returns multiple values.
How should I handle this case?
How about using in for the query instead of a variable?
BEGIN
UPDATE PROJECTS
SET TOUCHED = 1
WHERE ID IN (SELECT PJ_ID
FROM PROJECT_ROLES_GROUPS
WHERE GRP_ID = :NEW.GRP_ID
);
END