rajesh@ORA11G> create table emp as select * from scott.emp;
Table created.
rajesh@ORA11G> create table dept as select * from scott.dept;
Table created.
rajesh@ORA11G> update ( select ename,dname
2 from emp e, dept d
3 where e.deptno = d.deptno )
4 set ename = dname;
set ename = dname
*
ERROR at line 4:
ORA-01779: cannot modify a column which maps to a non key-preserved table
The error message tell us that "deptno" column in dept table is not unique. so each and every record from emp table could join with more than one record in Dept table.
let say deptno=10 is repeated twice in dept table with different department names and emp table has three employees working for deptno=10 then join between these two tables would produce six rows in the output, database has no clue about which department name should be updated here. Hence this error message.
if update is turned into a merge, then we don't see this error message.
rajesh@ORA11G> merge into emp using dept
2 on (emp.deptno = dept.deptno)
3 when matched then
4 update set ename = dname;
14 rows merged.
rajesh@ORA11G> rollback ;
Rollback complete.
rajesh@ORA11G>
that doesn't mean merge are solution to this case, the moment we insert deptno=10 twice into the dept table, then merge would result into an error like this.
rajesh@ORA11G> insert into dept
2 select *
3 from dept
4 where deptno = 10;
1 row created.
rajesh@ORA11G>
rajesh@ORA11G> merge into emp using dept
2 on (emp.deptno = dept.deptno)
3 when matched then
4 update set ename = dname;
merge into emp using dept
*
ERROR at line 1:
ORA-30926: unable to get a stable set of rows in the source tables
rajesh@ORA11G> rollback ;
Rollback complete.
rajesh@ORA11G>
the only difference here is UPDATE does this check before execution, while MERGE does this as part of statement execution.
The right way to avoid this error is define either a primary key or a unique index/constraint on dept(deptno). That way deptno is not duplicated in DEPT table and every record from EMP table matches at most zero or one record in DEPT table.
rajesh@ORA11G> alter table dept add constraint dept_pk
2 primary key(deptno);
Table altered.
rajesh@ORA11G> update ( select ename,dname
2 from emp e, dept d
3 where e.deptno = d.deptno )
4 set ename = dname;
14 rows updated.
rajesh@ORA11G> rollback ;
Rollback complete.
rajesh@ORA11G> merge into emp using dept
2 on (emp.deptno = dept.deptno)
3 when matched then
4 update set ename = dname;
14 rows merged.
rajesh@ORA11G> rollback;
Rollback complete.
rajesh@ORA11G>
rajesh@ORA11G> alter table dept drop constraint dept_pk;
Table altered.
rajesh@ORA11G> create unique index dept_pk on dept(deptno);
Index created.
rajesh@ORA11G> update ( select ename,dname
2 from emp e, dept d
3 where e.deptno = d.deptno )
4 set ename = dname;
14 rows updated.
rajesh@ORA11G> rollback ;
Rollback complete.
rajesh@ORA11G> merge into emp using dept
2 on (emp.deptno = dept.deptno)
3 when matched then
4 update set ename = dname;
14 rows merged.
rajesh@ORA11G> rollback;
Rollback complete.
rajesh@ORA11G>