Reputation: 1310
I have a view created in an Oracle 11g database that is comprised of two joined tables like so:
CREATE FORCE VIEW my_dataview
(
key1,
key2,
column_from_table1,
column_from_table2
)
AS
SELECT key1,
key2,
column_from_table1,
column_from_table2
FROM table1
NATURAL LEFT OUTER JOIN table2;
where both source tables have two primary keys named key1
and key2
. The data is being aggregated correctly, but I cannot update any of the columns from table2
directly from the view.
If I were to execute the following update,
UPDATE my_dataview SET column_from_table2 = 'Hello, world'
WHERE key1 = 1234
AND key2 = 12;
the error it gives is ORA-01779 cannot modify a column which maps to a non key-preserved table
. It also highlights column_from_table2
. If I were to execute the same command, but set column_from_table1
instead, it works. I think that may be because table1 is the required table in the join.
I first thought that maybe since I'm joining on the primary keys, and there is only one resulting column in the view, that would explain my problem. But even adding in the separate table2.key1
and table2.key2
columns to the view did not change anything, except replicating data unnecessarily.
I know it is possible to update a view using an INSTEAD OF trigger, but I would prefer to keep this as clean I can -- that seems more like a hack than a solution anyways.
So to summarize my question, what is the best plan of action for enabling insert, update, and delete on a join view so as to not even be able to tell it is a view comprised of two separate tables at all?
Table definitions as requested:
CREATE TABLE table1
(
key1 NUMBER(5) NOT NULL,
key2 NUMBER(2) NOT NULL,
column_from_table_1 DATE
);
CREATE UNIQUE INDEX pk_table1_index ON table1
(key1, key2);
ALTER TABLE table1 ADD (
CONSTRAINT table1_Pkey
PRIMARY KEY
(key1, key2)
USING INDEX pk_table1_index
ENABLE VALIDATE);
CREATE TABLE table2
(
key1 NUMBER(5) NOT NULL,
key2 NUMBER(2) NOT NULL,
column_from_table_2 VARCHAR2(20)
);
CREATE UNIQUE INDEX pk_table2_index ON table2
(key1, key2);
ALTER TABLE table2 ADD (
CONSTRAINT table2_Pkey
PRIMARY KEY
(key1, key2)
USING INDEX pk_table2_index
ENABLE VALIDATE);
Upvotes: 3
Views: 4458
Reputation: 36107
You cannot update column_from_table2
in this view, it's not updatable.
To check whether some column is updatable or not, run this query:
SELECT * FROM USER_UPDATABLE_COLUMNS
WHERE table_name = 'MY_DATAVIEW';
OWNER TABLE_NAME COLUMN_NAME UPDATABLE INSERTABLE DELETABLE
------------------------------ ------------------------------ ------------------------------ --------- ---------- ---------
TEST MY_DATAVIEW KEY1 YES YES YES
TEST MY_DATAVIEW KEY2 YES YES YES
TEST MY_DATAVIEW COLUMN_FROM_TABLE1 YES YES YES
TEST MY_DATAVIEW COLUMN_FROM_TABLE2 NO NO NO
Why it is not updatable ? It's a big question.
There is a whole chapter in documentation on this topic:
http://docs.oracle.com/cd/B28359_01/server.111/b28310/views001.htm#i1006234
find "Updating Views That Involve Outer Joins", there is an example of a view with outer join and detailed explanation which columns in this view can and cannot be updated and why.
Upvotes: 3
Reputation: 25753
Try to change your view to this:
CREATE FORCE VIEW my_dataview
(
key1,
key2,
column_from_table1,
column_from_table2
)
AS
SELECT t1.key1,
t1.key2,
t1.column_from_table1,
t2.column_from_table2
FROM table1 t1
LEFT OUTER JOIN table2 t2 on t1.key1 = t2.key1
and t1.key2 = t2.key2;
Upvotes: 0