简体   繁体   中英

How to avoid ORA-01427 in update statement?

I know below subquery should return 1 row. Can you let me know how to change below UPDATE query to update test1 table with mapping table's rows?

update test1 a set daily_value = ( select daily_value from mapping b where a.table_name = b.table_name);
                              *
ERROR at line 1:
ORA-01427: single-row subquery returns more than one row


create table test1
( table_name varchar2(10),
  daily_value varchar2(10)
)
/

insert into test1(table_name) values ('first');
insert into test1(table_name) values ('first');
commit;


create table mapping
( table_name varchar2(10),
  daily_value varchar2(10)
)
/

insert into mapping values ('first','value_1');
insert into mapping values ('first','value_2');
commit;



TEST1 table should have below data

TABLE_NAME  DAILY_VALUE
FIRST       value_1
FIRST       value_2

You need to decide on ordering criteria on your tables to decide which rows gets value_1 and which one gets value_2 . Assuming you have no ordering, a simple rownum could work; for example:

merge into test1 t1
using( select daily_value, table_name, rownum as rn 
       from mapping
     ) M
on (M.table_name = t1.table_name and rownum = M.rn)     
when matched then 
    update set daily_value = M.daily_value    

gives:

TABLE_NAME DAILY_VALUE
---------- -----------
first      value_1    
first      value_2

The update cannot return 1 row as it cannot distinguish both rows in table test1 as they have the same value 'first'. If you change the data to have different values, it works as expected:

DELETE FROM mapping;
DELETE FROM test1;

INSERT INTO test1(table_name) VALUES ('first');
INSERT INTO test1(table_name) VALUES ('second');

INSERT INTO mapping VALUES ('first','value_1');
INSERT INTO mapping VALUES ('second','value_2');

update test1 a set daily_value = ( select daily_value from mapping b where a.table_name = b.table_name);
2 rows updated.

Personally, I prefer the MERGE statement, though, as I find it a bit clearer:

MERGE INTO test1 USING mapping 
   ON (test1.table_name = mapping.table_name)
 WHEN MATCHED THEN UPDATE SET 
      test1.daily_value = mapping.daily_value; 

One option is to select MIN or MAX of (daily_value)

UPDATE test1 a
SET
    daily_value = (
        SELECT
            MIN(daily_value)
        FROM
            mapping b
        WHERE
            a.table_name = b.table_name
    );

But, this will make your data in test1 like this

TABLE_NAME  DAILY_VALUE
first   value_1
first   value_1

If you don't want this, you should add another unique column which relates between the two tables other than table_name

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM