UPDATE trigger affects all rows - sql

I'm having trouble when I updated my values with a trigger.
Here is my trigger function
CREATE OR REPLACE FUNCTION insert_check_item()
RETURNS trigger AS
$$
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO invoice_item(name, quantity, item_id, total, invoice_id)
SELECT i.name, NEW.quantity, NEW.item_id, NEW.quantity * i.price, NEW.invoice_id
FROM item i
WHERE new.item_id = i.item_id;
ELSEIF TG_OP = 'UPDATE' THEN
UPDATE invoice_item
SET total = NEW.quantity * i.price,
quantity = NEW.quantity
FROM item i
WHERE old.item_id = i.item_id;
END IF;
RETURN NULL;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_total
BEFORE INSERT OR UPDATE
ON invoice_item
FOR EACH ROW
WHEN (pg_trigger_depth() < 1)
EXECUTE PROCEDURE insert_check_item();
My table invoice_item depends on item to have the name and total amount

I added this other where clause to my update and solved the problem
ELSEIF TG_OP = 'UPDATE' THEN
UPDATE invoice_item
SET total = NEW.quantity * i.price,
quantity = NEW.quantity
FROM item i
WHERE invoice_item.item_id = i.item_id AND invoice_item.invoice_item_id = NEW.invoice_item_id;

You are overcomplicating things. There is no need to replace the original INSERT or UPDATE operation if you just want to change the value of a column.
You can simply assign the needed value to the column in the NEW record.
CREATE OR REPLACE FUNCTION insert_check_item()
RETURNS trigger AS
$$
DECLARE
l_price numeric;
BEGIN
select i.price
into l_price
from item i
where i.item_id = new.item_id;
new.total := new.quantity * l_price;
RETURN new;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_total
BEFORE INSERT OR UPDATE
ON invoice_item
FOR EACH ROW
EXECUTE PROCEDURE insert_check_item();

Related

Postgres insert trigger to update multiple columns on new row if null

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 can not understand what is this syntax error in my SQL trigger function (Postgres SQL)

I received this syntax error in Postgres SQL
ERROR: syntax error at or near ";"
LINE 41: end;
^
SQL state: 42601
Character: 1807
Far as I know, this "end" is correct in syntax
I cannot understand what wrong here?
Can anyone help me figure it out?
Here are my SQL queries in Postgres SQL
--Trigger update ave_imported_price after insert, update, delete in invoice_item
--create a view (item_id, total_imported_quantity) for later use
create or replace view item_with_quantity as
select item_id, sum(ii2.quantity) as qty
from item i2 inner join invoice_item ii2 using(item_id)
inner join item_order io using(item_id)
where i2.state = 1
group by (item_id);
--trigger function
create or replace function func_update_ave_imported_price_when_change_invoice_item() returns trigger as
$$ declare
var_qty int; --total qty
begin
if TG_OP = 'insert' then
select qty into var_qty from item_with_quantity where item_id = new.item_id;
-- update ave_imported_price
-- new_ave_price = ((old_total_qty*old_ave_price)+ (new.qty*new.imported_price)) / new_total_qty
update item set ave_imported_price = ((var_qty*ave_imported_price)
+ (new.quantity*new.imported_price)) / (var_qty + new.quantity)
where item.item_id = new.item_id;
return new;
else if TG_OP = 'update' then
select qty into var_qty from item_with_quantity where item_id = new.item_id;
-- update ave_imported_price
-- updated_ave_price = ((old_total_qty*old_ave_price) - (old.qty*old.imported_price)
-- + (new.qty*new.imported_price)) / (old_total_qty - old.qty + new.qty)
update item set ave_imported_price = ((var_qty*ave_imported_price) - (old.quantity*old.imported_price)
+ (new.quantity*new.imported_price)) / (var_qty - old.quantity + new.quantity)
where item.item_id = new.item_id;
return new;
else if TG_OP = 'elete' then
select qty into var_qty from item_with_quantity where item_id = new.item_id;
-- update ave_imported_price
-- ave_price = ((old_total_qty*old_ave_price) - (old.qty*old.imported_price)) / new_total_qty
update item set ave_imported_price = ((var_qty*ave_imported_price)
- (old.quantity*old.imported_price)) / (var_qty - old.quantity)
where item.item_id = new.item_id;
return old;
end if;
end;
$$ language plpgsql;

I want to create trigger but I dont know how to do that. Below is the sample

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;

Error on create trigger on PostreSQL

I'm trying to import this trigger into a postgre database but i got an error.
This is my code
Select "comandes.before_insert_detall" AS "05";
DROP TRIGGER IF EXISTS before_insert_detall;
DELIMITER --
CREATE TRIGGER before_insert_detall BEFORE INSERT ON detall
FOR EACH ROW
BEGIN
Declare stock INT;
SET stock = (select existencias from productos where id_fab=NEW.fab AND id_producto = NEW.producto);
IF NEW.cantidad > stock THEN
SET NEW.cantidad = stock;
END IF;
SET NEW.preu = (select precio from productos where id_fab=NEW.fab AND id_producto = NEW.producto);
END;
--
DELIMITER ;
I've already checked the fields name's and are ok. Can anyone help me?
Thanks
Try with SELECT INTO
SELECT INTO stock
existencias
FROM productos
WHERE ....
I found the answer!There's the correct code:
CREATE OR REPLACE FUNCTION F_before_insert_detall() RETURNS TRIGGER AS $F_before_insert_detall$
Declare stock INT;
BEGIN
stock = (select existencias from productos where id_fab=NEW.fab AND id_producto = NEW.producto);
IF NEW.cantidad > stock THEN
NEW.cantidad := stock;
END IF;
NEW.preu := (select precio from productos where id_fab=NEW.fab AND id_producto = NEW.producto);
RETURN NEW;
END;
$F_before_insert_detall$ LANGUAGE plpgsql;
CREATE TRIGGER before_insert_detall BEFORE INSERT ON detall FOR EACH ROW
EXECUTE PROCEDURE F_before_insert_detall();
Thank you so much anyway :)

How can I change the following procedure into an Instead Of trigger?

CREATE or REPLACE PROCEDURE UPDATE_SUBTOTAL is
v_order_no orderline.order_no%type;
v_subtotal number(15);
CURSOR product_orderline_cur is
SELECT ol.order_no, sum(p.unit_price * ol.qty) as subtotal
from product p, orderline ol
where p.product_no = ol.product_no
group by ol.order_no;
BEGIN
OPEN product_orderline_cur;
LOOP
FETCH product_orderline_cur into v_order_no, v_subtotal;
EXIT when product_orderline_cur%notfound;
-- store subtotal in orders table
UPDATE orders
SET subtotal = v_subtotal
WHERE order_no = v_order_no;
END LOOP;
--an order may be created but no orderlines added yet,insert a 0
UPDATE orders
SET subtotal = 0
WHERE subtotal is null;
CLOSE product_orderline_cur;
END;
/
show errors;
CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE ON orders
FOR EACH ROW
DECLARE v_sum INT;
BEGIN
SELECT SUM(p.unit_price * ol.qty)
INTO v_sum
FROM product p INNER JOIN orderline ol
ON p.product_no = ol.product_no
WHERE ol.order_no = :new.order_no;
:new.subtotal := COALESCE(v_sum, 0);
END;