Can someone help me implement the following trigger in PL/SQL Oracle? - sql

So,
I have 4 tables:
Suppliers( id_sup, name, city)
Products (id_prod, name, city)
Companies (id_co, name, city)
Deliveries (id_sup, id_prod, id_co)
I need a trigger so that if I want to update the city of a Supplier, I am not allowed if that supplier has a delivery where the product it delivers and the company it delivers to have the same city as it.
This is what I've tried so far, but it's not working:
CREATE OR REPLACE TRIGGER secure_suppliers
BEFORE UPDATE ON Suppliers
BEGIN
IF UPDATING ('city') THEN
IF (suppliers.id_sup IN (SELECT id_sup FROM Deliveries) AND suppliers.city = (Select p.city From Products p INNER JOIN Deliveries d ON (p.id_prod = d.id_prod)) AND suppliers.city = (Select c.city From Companies c INNER JOIN Deliveries d ON (c.id_co = d.id_co))) THEN
RAISE_APPLICATION_ERROR(-20500, 'Can't update city!');
End if;
End;

You can use one query to find if product, supplier and company are in one city with new value of the supplier then proceed with error handling in the trigger as following:
CREATE OR REPLACE TRIGGER secure_suppliers
For each row -- row level trigger
BEFORE UPDATE OF city ON Suppliers -- trigger will execute on update of column city only
DECLARE
cnt NUMBER := 0;
BEGIN
select count(1)
Into cnt
From deliveries d
Join companies c on d.id_co = c.id_co
Join products p on d.id_prod = p.id_prod
Where p.city = c.city
And p.city = :new.city;
If cnt > 0 then
RAISE_APPLICATION_ERROR(-20500, 'Can''t update city!');
End if;
End;
/
Cheers!!

Related

Update multiple columns by ids

I have tables called tblPurchase and tblInvoice. When I Insert new record I want to update my TotalStock form tblInvoice. I tried following code.
Create procedure [dbo].[spUpdateTotalStock] #Stock int, #PurchaseId int
As
Begin
Begin Transaction
Update tblPurchase
Set TotalStock = #Stock
Where PurchaseId = #PurchaseId
RollBack Transaction
end
It worked as expected. But I want to update TotalStock column by many ids. It means when I insert more than one invoice at the same time, I want to update my TotalStock column. like this
tblInvoice
ItemName | Quantity
---------+----------
Phone 3
Mouse 6
tblPurchase
ItemName | TotalStock
-----------+------------
phone 3
Mouse 6
ID comes with parameter. Always more than 10 ids come with parameter.
When I Insert new record I want to update my TotalStock form tblInvoice
This would normally be handled via a trigger not a stored procedure. That would look something like this:
create trigger trig_invoice_update on tblInvoice
after insert, update, delete
begin
update p
set quantity = p.quantity + coalesce(i.quantity, 0) - coalesce(d.quantity, 0)
from tblPurchase p left join
(select i.itemName, sum(i.quantity) as quantity
from inserted i
group by i.itemName
) i
on p.itemName = i.itemName left join
(select d.itemName, sum(d.quantity) as quantity
from deleted d
group by d.itemName
) d
on p.itemName = d.itemName
where d.quantity <> 0 or i.quantity <> 0;
end;
This version handles inserts, updates, and deletes, but assumes that all items are already in the purchases table.

SQL query to copy the column value to another column after checking two conditions

I have a table customers, in which i have 6 attributes
CustomerID CustomerName CustomerCity CustomerState DuplicateCustIND
1 Richard Los Angeles New York
2 Jerome Houston Texas
3 Paul Los Angeles New York
In the above table, there are two duplicate column values CustomerCity and CustomerState are same for Richard and Paul. I would like to update the column DuplicateCustIND for paul with the customer id of Richard after checking the two similar column condition.
Till now I was using correlation query as
Update Customer C1 set C1.DuplicateCustIND = (select CustomerID from customers
where C3.CustomerCity =
C1.CustomerCity and
C3.CustomerState =
C1.CustomerState)
where exists(
Select 1 from Customers C2 where
C2.CustomerCity = C1.CustomerCity and
C2.CustomerState = C1.CustomerState and
C2.RowID<C1.RowID);
The above query didn't help me.
The below query could work.
merge INTO customers tgt USING
(SELECT a.id,
a.cname,
a.ccity,
a.cstate
FROM customers a,
(SELECT ccity,
cstate,
COUNT(*)
FROM customers b
GROUP BY ccity,
cstate
HAVING COUNT(*) > 1
) b
WHERE a.ccity = b.ccity
AND a.cstate = b.cstate
) src ON (tgt.id = src.id)
WHEN matched THEN
UPDATE SET tgt.dcustid = src.id;
You may probably rely on customerid and use a MERGE statement to update all records greater than that customerid with same city and state.
MERGE INTO customers t USING
( SELECT MIN(c1.CUSTOMERID) prim_id,
c2.CUSTOMERID sec_id
FROM Customers c1
JOIN customers c2 ON C2.CustomerCity = C1.CustomerCity
AND C2.CustomerState = C1.CustomerState
AND C2.CustomerID > C1.CustomerID
GROUP BY C1.CustomerCity,
C1.CustomerState,
c2.CUSTOMERID ) s ON (s.sec_id = t.CustomerID )
WHEN MATCHED THEN
UPDATE
SET t.DuplicateCustIND = s.prim_id;
SQLFiddle

Postgres trigger that affects rows with certain values

I'm postgres newbie and i have a question regarding triggers. Lets say we have 2 tables. One with cities and one with people.
CITIES:
PEOPLE:
I need a trigger that updates 'processed' value in table cities from 0 to 1 when 'processed' value in table people updates from 0 to 1 for all people from that city.
For example: John, Ian and Claire are from Berlin and when 'processed' value is updated to 1 for each of them, then the trigger updates processed value for Berlin in table cities to 1.
What is the best way to do this?
This will work:
CREATE OR REPLACE FUNCTION mytrigger() RETURNS TRIGGER AS $mytrigger$
BEGIN
IF (SELECT EXISTS (SELECT 1 FROM PEOPLE WHERE city_id = NEW.city_id AND processed = '0')) THEN
UPDATE CITIES SET processed = '0' WHERE id = NEW.city_id;
RETURN NEW;
ELSE
UPDATE CITIES SET processed = '1' WHERE id = NEW.city_id;
RETURN NEW;
END IF;
END;
$mytrigger$ LANGUAGE plpgsql;
CREATE TRIGGER mytrigger
AFTER UPDATE ON PEOPLE
FOR EACH ROW EXECUTE PROCEDURE mytrigger();
try this query:
with c as (
select city_id
from people
where name = NEW.name
)
, a as (
select avg(processed)
from people
join c on c.city_id = people.city_id
)
update cities u
set processed = 1
from a
where u.id = a.city_id
and avg = 1
alias c gets city id, then a aggregates processed for that sict id in people and lastly update updates only when all names are processed.

ORACLE SQL Status check trigger

I wanted to create a trigger which when a new order is inserted in the ORDERS table the trigger updates the status level of a customer in the CUSTOMER table, depending on how many orders they have made. If a customer has 0 orders his status level is 'new' else if he has more than 1 he is a 'standard' customer.
The trigger below works if I add the customer_no in manually:
create or replace TRIGGER STATUS_CHECK
AFTER INSERT ON ORDERS
DECLARE
n INT;
BEGIN
SELECT COUNT(ORDER_NO)
INTO n
FROM ORDERS
INNER JOIN CUSTOMER
ON CUSTOMER.CUSTOMER_NO = ORDERS.CUSTOMER_CUSTOMER_NO
WHERE CUSTOMER.CUSTOMER_NO = '01';
IF(n > 1) THEN
UPDATE CUSTOMER
SET CUSTOMER.STATUS_LEVEL = 'STANDARD'
WHERE CUSTOMER.CUSTOMER_NO = '01';
END IF;
END;

Joining Oracle ApEx collections to actual tables

Within Oracle ApEx is it possible to join an actual table in your schema to an Oracle ApEx Collection, as I am having trouble doing so?
Basically have the following scenario:
select c001, -- employee id from collection
c002,
c003 -- employee dept no from collection
from apex_collections,
emp
where emp.id = c001
and emp.deptno = c003;
Is the above possible or am I missing something?
we can join apex collection with our schema tables..it will work..
select c001, -- employee id from collection
c002,
c003 -- employee dept no from collection
from apex_collections,
emp emp
where emp.empno = c001
and emp.deptno = c003;
/*
I have this table person (personid, ...., telephone_numbers)
in which the column "telephone numbers" is a nested table.
In the example below I'm trying to use this into collections and display the count of telephone numbers that the row has.
-- */
DECLARE
telno telephone_number_table; -- variable name and type.
cnt INTEGER;
BEGIN
SELECT p.telephone_numbers -- accept the nested table into the variable
INTO telno
FROM person p
WHERE p.personid = 1;
SELECT COUNT(*) -- I'm using COUNT(*) here, you can use your valid column listing.
INTO cnt
FROM person p
CROSS JOIN TABLE(telno) tel -- use a cross join with alias
WHERE p.personid = 1;
dbms_output.put_line(cnt);
END;
/