Skip to Main Content
  • Questions
  • Updating records with many-to-1 linked table relationship

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Joseph.

Asked: September 27, 2017 - 2:52 pm UTC

Last updated: September 28, 2017 - 3:38 pm UTC

Version: 11g

Viewed 1000+ times

You Asked

I have an MS_ACCESS Query to convert to Oracle SQL.

Access Query

UPDATE target_table T 
INNER JOIN source_table S 
ON T.linkcolumn = S.linkColumn
SET 
T.field1 = S.field1, 
T.field2 = S.field2,
T.field3 = S.field3;


Note: This query updates records even though there is a 1-to-many relationship between the Source (1) and the target (many)
----------------------------------------------------

Oracle SQL
This code produces an "unable to get stable set of rows" error because
the target table has instances of many records in the target table matching one record in the source table

MERGE INTO target_table T
USING ( 
    SELECT *
    FROM source_table 
    ) S
ON   
(
T.manyRecsLinkColumn = S.oneRecLinkColumn  
)
WHEN MATCHED THEN 
UPDATE SET 
    T.columnToUpdate1 = S.Value1,
    T.columnToUpdate2 = S.Value2,
    T.columnToUpdate3 = S.Value3

-------------------------------------------------------

Alternate Approach In Access using VBA script (Pseudo Code)

Dim strFieldValue as String
Dim myDB as database
Dim rsSource, rsTarget as Recordset

Set rsSource = myDB.openRecordset(source_table)
Set rsTarget = myDB.openRecordset(target_table, dbOpenDynaset)

rsSource.moveFIRST     ' Start at 1st record
Do while not rsSource.EOF     ' Begin Row by Row Scan
 strFieldValue = rs!Source!MyValue
 rsTarget.findFIRST " rsTarget.FieldName  = 'strFieldValue' "
 if NOT rsTarget.noMatch    ' it is a match
  Update rsTarget!Column1 = rsSource!Column1
  Update rsTarget!Column2 = rsSource!Column2
  Update rsTarget!Column3 = rsSource!Column3
 else         ' it is not a match
  Goto NextRecord
 endif
LookForMore:
 rsTarget.findNEXT " rsTarget.FieldName  = 'strFieldValue' "
 if NOT rsTarget.noMATCH    ' it is a match
  Update rsTarget!Column1 = rsSource!Column1
  Update rsTarget!Column2 = rsSource!Column2
  Update rsTarget!Column3 = rsSource!Column3
  Goto LookForMore
 endif
NextRecord:      ' no more matches
 rsSource.moveNEXT    ' Move to next Source record
Loop       ' Repeat until End-of-Table

------------------------------------------------------------

Questions:

1. Is there an Oracle SQL statement, perhaps a refinement of the Oracle Code above, which will Update multiple records when there is
1-to-many relationship between the source (1) and target (many)

2. If a Stored Procedure is the only approach, could you provide a general look of that procedure that is probably similar to the ACCESS VBA script above.



and Chris said...

So you have one row in your source table that matches with many in the target?

You can "update the join" in Oracle Database.

Provided you have a primary or unique key on the join columns!

create table t1 (
  x int,
  c1 int,
  c2 int, 
  c3 int
);
create table t2 (
  x int ,
  c1 int,
  c2 int, 
  c3 int
);

insert into t1 values (1, 1, 1, 1);
insert into t2 values (1, 0, 0, 0);
insert into t2 values (1, 2, 2, 2);
insert into t2 values (1, 4, 4, 4);
commit;

select * from t2;

X  C1  C2  C3  
1  0   0   0   
1  2   2   2   
1  4   4   4  

update (
  select t1.c1 c11, t2.c1 c12 ,
         t1.c2 c21, t2.c2 c22 ,
         t1.c3 c31, t2.c3 c32 
  from   t1 join t2 on t1.x = t2.x
)
set c12 = c11, c22 = c21, c32 = c31;

SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table

select * from t2;

X  C1  C2  C3  
1  0   0   0   
1  2   2   2   
1  4   4   4 

alter table t1 add primary key (x);

update (
  select t1.c1 c11, t2.c1 c12 ,
         t1.c2 c21, t2.c2 c22 ,
         t1.c3 c31, t2.c3 c32 
  from   t1 join t2 on t1.x = t2.x
)
set c12 = c11, c22 = c21, c32 = c31;

select * from t2;

X  C1  C2  C3  
1  1   1   1   
1  1   1   1   
1  1   1   1 


Or you could go for a correlated update:

rollback;

update t2
set    (c1, c2, c3) = (
  select c1, c2, c3 from t1
  where  t1.x = t2.x
);

select * from t2;

X  C1  C2  C3  
1  1   1   1   
1  1   1   1   
1  1   1   1 

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Update

Joseph Giallombardo, September 28, 2017 - 4:20 pm UTC

Chris,

Understood. Very help full I give the primary key approach a try.

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.