ORACLE - Update table if exists else insert use rownum to match - oracle

I have table master (A) without field ID_No. So i create table B (copy from A) and set B.ID_No = rownum.
Now i want update B if A exist else will insert B with B.ID_NO = A.rownum
In oracle can create query with B.ID_NO = A.rownum?
My logic is ID of B = rownum of A, row++ then ID++, row have change value then fields ID will update.

For rownum repeatability is not guaranteed. You should find unique column or combination of columns for key in tables A and B, for a one-to-one relationship.

Related

adding data from two different tables using a trigger

I created three tables A (id, name, date, realnumber, integer), B (id, name, date, realnumber, integer), and C which is identical to table A. It only has two more columns called integerB and sequence s. I want to create a trigger which would fire after insert on table B for each row input so that it saves the referenced row of Table A and adds integer from input row of table B in column integerB of table C. If the row already exists in Table C only integerB should be added. When it comes to sequence s, next value is added with first insert of row of table A.
Simple explanation: Table C is a copy of table A with two additional columns: integerB and sequence. The point of the trigger is to add new rows from table A without repetition, integerB from table B(integer in table B) and sequence should start with 1 and increment by 1. If the row in table A is repeated then only integerB should be updated.
I did not work with triggers that much, so I am not sure how to solve the problem when I have to insert data from multiple tables. Here is my trigger.
CREATE OR REPLACE TRIGGER trig1
AFTER INSERT ON B
FOR EACH ROW
INSERT INTO C (integerB) VALUES (NEW.integer);
INSERT INTO C (id, name, date, realnumber)
SELECT a.id, a.name, a.date, a.realnumber FROM A a;
END;
/
First off you really need to use better column and table names as a lot of these are reserved words... This makes everything far more complicated than it needs to be.
It isn't entirely clear what you want to do but it seems that if someone was to insert a record with ID = 1 into B then you want to get the values from A for ID = 1 and store them in C along with the integer value inserted into B
In which case you want to use an MERGE statement (UPSERT) in your trigger and something like
CREATE OR REPLACE TRIGGER T1
AFTER INSERT ON B
FOR EACH ROW
BEGIN
MERGE INTO C C
USING (SELECT * FROM A WHERE ID = :NEW.ID) A
ON (C.ID = :NEW.ID)
WHEN MATCHED THEN UPDATE
SET C.INTEGERB = :NEW.INTEGER,
C.SEQUENCE = C.SEQUENCE + 1
WHEN NOT MATCHED THEN
INSERT (ID, NAME, DATE, REALNUMBER, INTEGER, INTEGERB, SEQUENCE)
VALUES (A.ID, A.NAME. A.DATE, A.REALNUMBER, A.INTEGER, :NEW.INTEGER, 0);
END;
/
For sequence this has been set to 0 when a new record is inserted into C and then incremented each time integerB is updated. I am not sure if this is waht you want or not.
You should be able to tweak this to match the exact joins and logic you need.
Tip
Get your SQL statement working with literal values first and then translate it into your trigger. It will be much easier if you can get something working manually first before you attempt to make things more complicated

PL/SQL: I have problem updating a table with data from another table

First table ROOMDB:
roomnumber
rentalbalance
N327
0
Second table RENTALINVOICE:
invoicedate
roomnumber
totaldue
11/26/2021
N327
2,200.00
My update code:
UPDATE ROOMDB
SET
RENTALBALANCE = (SELECT TOTALDUE
FROM RENTALINVOICE
WHERE RENTALINVOICE.ROOMNUMBER=ROOMDB.ROOMNUMBER
AND INVOICEDATE=SYSDATE) ;
I need to update the totaldue column in ROOMDB with data from RENTALINVOICE though it successfully enters 2,200 to the totaldue column, AT THE SAME TIME IT ALSO WIPES OUT THE REST OF THE RECORDS on this column in ROOMDB.
Everytime I update it, it erases the rest of the records except the roomnumber I specified. Please help.
You basically seem to also updates rows in table roomdb where there is no row in table rentalinvoice and therefore the column rentalbalance will be set to null.
Have a look a following example:
drop table a;
create table a (id number, cost number);
insert into a values (1, 1);
insert into a values (2, 2);
drop table b;
create table b (id number, cost number);
insert into b values (1, 100);
-- updates all rows in a and sets cost to null whenen there is no row in b
update a set cost = (select cost from b where a.id = b.id);
select * from a;
-- only updaes rows in a where there is a row in b
update a set cost = id;
update a set cost = (select cost from b where a.id = b.id) where exists (select 1 from b where a.id = b.id);
select * from a;
When you execute an update command like this Oracle will update all the table rows. For every row Select command will execute with these row values. If the result of select in the update does not find any record will return null. In this situation the RENTALBALANCE column will set null too.
(SELECT TOTALDUE
FROM RENTALINVOICE
where WHERE RENTALINVOICE.ROOMNUMBER = ROOMDB.ROOMNUMBER
AND INVOICEDATE = SYSDATE)

oracle stored procedure updating one table with the help of another table

TABLE A : name empid activeind
TABLE B : name empid activeind
update table A based on table B comparing empid from both the table using Oracle stored procedure
Here's one option.
create or replace procedure p_upd is
begin
merge into a
using b
on (b.empid = a.empid)
when matched then update set a.name = b.name,
a.activeind = b.activeind;
end;
/
[EDIT] Based on your comment: you used wrong syntax. UPDATE should be
UPDATE a
SET (a.name, a.activeind) =
(SELECT b.name, b.activeind
FROM b
WHERE b.empid = a.empid)
WHERE EXISTS
(SELECT NULL
FROM b
WHERE b.empid = a.empid);
Why exists? Without it, you'd set name and activeid values to null for all a.empid rows that don't exist in b table.

Update with 2 joins

I'm trying to update data in 2 distinct tables in the same query with the following code:
UPDATE (SELECT s.passNumb, a.hour, a.minute, p.number, s.situation
FROM passwords s
JOIN atend a ON s.passNumb = a.passNumb
JOIN points p ON a.number = p.number
WHERE s.passNumb = 1 AND
p.number = 1)
SET a.hour = TO_CHAR(SYSDATE, 'HH24'),
a.minute = TO_CHAR(SYSDATE, 'MI'),
s.situation = 'F';
But I'm getting this error: Cannot modify a column which maps to a non key-preserved table. What am I doing wrong?
A view with a join (or an inline view containing a join in your case) must meet the following conditions to be updatable:
https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_8004.htm
If you want a join view to be updatable, then all of the following
conditions must be true:
The DML statement must affect only one table underlying the join.
For an INSERT statement, the view must not be created WITH CHECK
OPTION, and all columns into which values are inserted must come from
a key-preserved table. A key-preserved table is one for which every
primary key or unique key value in the base table is also unique in
the join view.
For an UPDATE statement, the view must not be created WITH CHECK
OPTION, and all columns updated must be extracted from a key-preserved
table.
The first condition is rather obvious: The DML statement must affect only one table underlying the join.
But what does it mean: "key preserved table" ?
A key-preserved table is one for which every primary key or unique
key value in the base table is also unique in the join view.
The key preserved table means that each row from this table will appear at most once in the result of a view.
Consider a simple example:
CREATE TABLE users(
user_id int primary key,
user_name varchar(100),
age int
);
insert into users values(1,'Tom', 22);
CREATE TABLE emails(
user_id int,
email varchar(100)
);
Insert into emails values( 1, 'tom#somedomain.com' );
Insert into emails values( 1, 'tom#www.example.org' );
commit;
And a join:
SELECT *
FROM users u
JOIN emails e ON u.user_id = e.user_id;
USER_ID USER_NAME AGE USER_ID EMAIL
---------- --------------- ---------- ---------- --------------------
1 Tom 22 1 tom#somedomain.com
1 Tom 22 1 tom#www.example.org
If you look at a result of this join, it is apparent that:
user_id, user_name and age come from non-key preserved table
email comes from key-preserved table
And now: this update is acceptable, because it updates a key preserved column (table) in this join:
UPDATE (
SELECT * FROM users u
JOIN emails e ON u.user_id = e.user_id
)
SET email = email || '.it' ;
USER_ID USER_NAME AGE USER_ID EMAIL
---------- --------------- ---------- ---------- -------------------------
1 Tom 22 1 tom#somedomain.com.it
1 Tom 22 1 tom#www.example.org.it
But this update cannot be done, since it touches a column from non-key preserved table:
UPDATE (
SELECT * FROM users u
JOIN emails e ON u.user_id = e.user_id
)
SET age = age + 2;
SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table
01779. 00000 - "cannot modify a column which maps to a non key-preserved table"
*Cause: An attempt was made to insert or update columns of a join view which
map to a non-key-preserved table.
*Action: Modify the underlying base tables directly.
If you think a while .... Tom appears 2 times in the result of the join (but there is only one Tom in the users table).
When we are trying to update age = age + 2 in this join, then what should be a result of this update ?
Should Tom be updated only once ?
Should Tom be 22+2 = 24 years old after this update ?
Or maybe Tom should be updated twice (since it appears twice in the result of the join) so it should be 22 + 2 + 2 = 26 years old.
Another example - please tell me what should be an outcome of this update?:
UPDATE ( ....our join ... ) SET age = length( email );
There are very difficult questions :)
And because of this Oracle prevents from updating non-key preserved tables.
The error message gives this hint:
*Action: Modify the underlying base tables directly.
This means that we must update this table directly, using a separate UPDATE command:
UPDATE users SET age = age + 2

How to populate column data in one table based on an id match from another table (using the data from the matched table)

In Oracle I have two tables. Both are populated with data and have a timestamp column.
One table has that column filled with data, the other table doesn't. But I need to get the data from the table that does into the column of the other table based on a match of another column.
Each has 'code' so the timestamp from the one table should only be put in the timestamp of the other table where the codes match.
I've tried cursors etc, but it seems like I'm missing something.
Any suggestions?
It sounds like you want a correlated update. This will update every row of destinationTable with the timestamp_col from sourceTable where there is a match on the code column.
UPDATE destinationTable d
SET timestamp_col = (SELECT s.timestamp_col
FROM sourceTable s
WHERE s.code = d.code )
WHERE EXISTS( SELECT 1
FROM sourceTable s
WHERE s.code = d.code )
Just for completeness, I think I would have done something like this (untested), if the destination has a primary key or unique column:
UPDATE (
SELECT d.primary_key AS pk, d.timestamp_col AS dest_col, MAX(s.timestamp_col) AS src_col
FROM dest d
JOIN src s ON d.code = s.code
GROUP BY pk, dest_col
) j
SET j.dest_col = j.src_col

Resources