Oracle to trigger an update upon insertion in another table - plsql

i would like to have a situation whereby i have 2 tables, table 1 is customers table with salary column and table 2 is a tax table.
When i insert a record in the tax table with tax amount, i would like the amount to subtract the salary and the customer table (salary column) is update with the net salary.
CREATE OR REPLACE TRIGGER trig_update
AFTER INSERT ON tax
FOR EACH ROW
DECLARE
net_sal;
BEGIN
net_sal := :customers.salary - :tax.amount;
UPDATE customers (salary) VALUES (net_sal)
WHERE (tax.cust_id == customers.id);
END;
I am getting a compilation error

First, there is no "==" operator in SQL. Only "=".
Second, you need a SET clause in your update statement. It should be
UPDATE customers
SET salary = net_sal
WHERE tax.cust_id = customers.id;
Third, this is bad table design. Instead of updating the salary column, make a new column called "net_salary" and update that column instead. What if you had to delete a tax record and insert a new one? Your salary value would still have the old taxes taken from it, being incorrectly low.

Related

Need to delete/insert that corresponding row in that table, as there is duplicate data coming up- PLSQL

I need a help in getting the PLSQL procedure to : Insert/Delete the rows of a table , because as I used Update functionality getting duplicates for that particular Sequence ID field.
So for a particular sequence ID row, whenever I insert the data, it should be the latest in that table.
The last sentence you wrote suggests that you have to
delete row(s) whose ID equals that particular "sequence ID" value
then insert a new row
If you expected some code to be written, you should have posted some more info (CREATE TABLE and INSERT INTO sample data, as well as the way you manipulate it by inserting new row, showing what you expect to happen with old one(s)). It is difficult to write code based on unknown data model.
A guess...
INSERT INTO schema_name.table_name(
primary_key_column
, other_column
)
VALUES(
(SELECT max(primary_key_column)+1 FROM schema_name.table_name),
, 'other_value'
);
COMMIT;
This is the procedure I am using:
https://drive.google.com/file/d/1eGbxSppjexpICKh6pzuW0ZzckVxA6BB0/view?usp=sharing
My requirement when we need to insert the new data , the previous data should be deleted for the corresponding ID.
In the above procedure I am updating the data.

How to insert values in a table based on values in another table

I need to insert extra records in one table for all entries in another table where a certain condition is not met, namely they do not exist yet in the table.
I have 3 tables, one is called ARTICLES, and has columns (ArtNr, ArtName), the second table is called CUSTOMERS with columns (CustNr, CustName, CustAddress)
The third table CUSTARTLINK is a link between the Customer and Article tables and has a record for each Customer and all Article is has. So it has columns (CustNt, ArtNr).
This way, in the application, when a customer is selected, only the articles will be shown that have a Link with the customer in the table .
All this functionality is working, including adding and deleting articles and customers in the resp. tables, and adding articles to customers (creating entries in the CUSTARTLINK table.
I want to add a functionality that I can select one Article from the Articles table and add this to ALL the customers existing in the CUSTOMERS table (so creating new entries in the CUSTARTLINK table, as long as they not already exist.
I tried to create this with the INSERT into command combined with a WHERE condition, but I am not getting close to what I want to reach.
Can anyone list the SQL commands to reach this?
Suppose that you want to insert the artnr = 11 for all customers:
insert into custartlink (custnr, artnr)
select c.custnr, 11
from customers c
where not exists (
select 1 from custartlink
where custnr = c.custnr and artnr = 11
)
The condition where not exists... makes sure that there will be no duplicates after the statement is executed, or if there is already a constraint in the table custartlink that there will be no error trying to violate the constraint.
The same can be achieved with the use of except:
insert into custartlink (custnr, artnr)
select custnr, 11
from customers
except
select custnr, 11
from custartlink
where artnr = 11
If you have the article's name like 'art11' and you want to use that and not the artnr, then you can do this:
insert into custartlink (custnr, artnr)
select
c.custnr,
(select artnr from articles where artname = 'art11')
from customers c
where not exists (
select 1 from custartlink
where
custnr = c.custnr
and
artnr = (select artnr from articles where artname = 'art11')
)
INSERT INTO CUSTARTLINK (CustNt, ArtNr)
(SELECT CustNr, X from CUSTOMERS)
Replace X with article ID

Denormalization - maintaining redundancy by using triggers in Oracle

I have a task for my university project where I have denormalized a table and now I have to implement a trigger in order to maintain redundancy. After following the book accordingly I'm stuck on the last step and I can't get my mind around it.
I have two tables - Supplier and Catalogue
**Supplier**
SupplierCode (primary key)
SupplierName
**Catalogue**
SupplierCode (foreign key)
CatalogueCode (both SupplierCode and CatalogueCode form a primary key)
CatalogueName
DateCreated
SupplierName (redundant column for denorm purposes)
When a new row is inserted in the Catalogue table I want that SupplierName field in the same table gets populated based on the SupplierCode which was inserted.
What I have so far:
We need to create a package as well
create or replace PACKAGE "PACK" AS
SUPPCODE NUMBER:=0;
SUPPNAME VARCHAR2(50);
END;
I have created a BEFORE INSERT TRIGGER on Catalogue table
create or replace TRIGGER CatalogueBefore
BEFORE INSERT OR UPDATE ON CATALOGUE
FOR EACH ROW
BEGIN
PACK.SUPPCODE:=:NEW.SUPPLIERCODE;
END;
I've then added an AFTER INSERT TRIGGER on Catalogue table
create or replace TRIGGER "AddNewCatalogue"
AFTER INSERT ON CATALOGUE
FOR EACH ROW
DECLARE
V_SUPPNAME SUPPLIER.SUPPLIERNAME%TYPE;
BEGIN
SELECT SUPPLIERNAME INTO V_SUPPNAME
FROM SUPPLIER
WHERE SUPPLIERCODE= PACK.SUPPCODE;
PACK.SUPPNAME:=V_SUPPNAME;
END;
After all of this I have the Supplier name held in my package in PACK.SUPPNAME but my question is how do I now use this variable when inserting a new row in the Catalogue table? I'm stuck at this for some time now and I'm probably missing something obvious. :) Any help is appreciated. Thanks.
P.S Please ignore uppercase vs. lowercase letters - I've just translated the names from my native language. :)
Thanks
I have denormalized a table and now I have to implement a trigger in order to maintain redundancy
[...]
When a new row is inserted in the Catalogue table I want that SupplierName field in the same table gets populated based on the SupplierCode which was inserted.
If those are your only requirements, all you need is one trigger to alter the record with the data from the second table. Something like that, maybe:
CREATE OR REPLACE TRIGGER CatalogueBefore
BEFORE INSERT OR UPDATE ON Catalogue
FOR EACH ROW
BEGIN
SELECT S.SupplierCode INTO :NEW.SupplierCode
FROM Supplier S
WHERE S.SupplierName = :NEW.SupplierName;
END;
That way, on update or insert into the table Catalogue, the SupplierCode will be overwritten by the code coming from Supplier table. See http://sqlfiddle.com/#!4/d79e0/1 for a live example.
Some notes though:
For this to work, Supplier.SupplierName should be an unique index too. In fact, the all thing is based on the assumption this is a natural key.
You very probably need an other trigger to deal with updates in the Supplier table. Say, when one supplier's name will change, the new name will have to be propagated to Catalogue.

PL/SQL Triggers to update selected rows in column in another table

I'm trying to create a trigger for my 'rentals' table that will change the value in a certain column ('rent_avail') from another table when an update occurs in the former table. The idea is simple: when a dvd is returned to the dvd store (i.e. date_return has a date value, the dvd has now become available again for renting. Thus, my 'rent_avail' column for the record (dvd) in question should reflect this by being set to 'Y' (the alternative is 'null' when the dvd is currently being rented out). My trigger is being created without errors, but after an insert on the date_return column, all values in my DVD table are being changed. I want to know how can I simply modify the column values in 'rent_avail' column in my dvd table for only the row being updated! This is probably very trivial, but I have researched it and can't seem to find a solution easily..
CREATE OR REPLACE TRIGGER RENTAL_RETURNS
AFTER UPDATE OF DATE_RETURN ON RENTAL
FOR EACH ROW
BEGIN
IF :OLD.DATE.RETURN IS NULL AND :NEW.DATE_RETURN IS NOT NULL THEN
UPDATE DVD SET RENT_AVAIL = 'Y' WHERE DVD.DVD_ID = DVD_ID;
END IF;
END;
/
your update statement is not picking dvd_id from parent table rebtal, but evaluating like where dvd_id = dvd_id which will always be TRUE. Just ad :OLD qualifier and you should be good, considering this is same column name (dvd_id) in rental table.
CREATE OR REPLACE TRIGGER RENTAL_RETURNS
AFTER UPDATE OF DATE_RETURN ON RENTAL
FOR EACH ROW
BEGIN
IF :OLD.DATE.RETURN IS NULL AND :NEW.DATE_RETURN IS NOT NULL THEN
UPDATE DVD SET RENT_AVAIL = 'Y' WHERE DVD.DVD_ID = :OLD.DVD_ID;
END IF;
END;
It looks to me like there's a period where there should be an underscore in the IF statement - I think it should read
IF :OLD.DATE_RETURN IS NULL AND :NEW.DATE_RETURN IS NOT NULL THEN`
Share and enjoy.

How to create database table dynamically and insert data selected by query

I'm working on website where I need to find rank of user on the basis of score. Earlier I'm calculating the score and rank of user by sql query .
select * from (
select
usrid,
ROW_NUMBER()
OVER(ORDER BY (count(*)+sum(sup)+sum(opp)+sum(visited)*0.3) DESC) AS rank,
(count(*)+sum(sup)+sum(opp)+sum(visited)*0.3 ) As score
from [DB_].[dbo].[dsas]
group by usrid) as cash
where usrid=#userid
Please don't concentrate more on query because this is only to explain how I select data.
Problem: Now I can't use above query because every time I use rank it need to select rank from dsas table and data of dsas table is increasing day by day and slows down my website.
What I need is select data by above query and insert in another table named as score. Can we do anything like this?
A better solution is to either include score as a field in your user table or have a separate table for scores. Any time you add new sup, opp, or visited data for a user, also recalculate their score at that time.
Then to get the highest ranking users, you will be able to perform a very simple select statement, ordering by score descending, and only fetching the number of rows you want. It will be very fast.

Resources