简体   繁体   中英

SQL error ORA 01427 - Subquery returns more than 1 row resulted from update statement

Anyone can help me correct this SQL query below? I got error that says subquery return more than 1 row. Thanks.

UPDATE LINEITEM a
SET a.l_manufacturer_name=(with NAMES as (SELECT CASE
    WHEN MOD(b.L_PARTKEY,2)=0 THEN (SELECT M_NAME FROM MANUFACTURER m WHERE ROWNUM=1)
    WHEN MOD(b.L_PARTKEY,2)=1 THEN (SELECT M_NAME FROM (SELECT M_NAME, ROWNUM AS MYROW FROM (SELECT M_NAME, ROWNUM FROM MANUFACTURER m)) WHERE MYROW=2)
END AS MANUFACTURER_NAME FROM LINEITEM b)
SELECT MANUFACTURER_NAME FROM NAMES N WHERE N.L_PARTKEY=A.L_PARTKEY;

Actually, the error message is obvious( Too_Many_Rows exception raised due to the returning results for at least one select statement has more than one row ). In such cases an aggregate function may help us depending on our situation :

SQL> CREATE TABLE MANUFACTURER(M_NAME varchar2(75));
SQL> CREATE TABLE LINEITEM(l_manufacturer_name varchar2(75),l_partkey int);

SQL> INSERT INTO MANUFACTURER VALUES('abc');
SQL> INSERT INTO MANUFACTURER VALUES('def');
SQL> INSERT INTO LINEITEM VALUES('abc',1);
SQL> INSERT INTO LINEITEM VALUES('def',2);
SQL> INSERT INTO LINEITEM VALUES('abc',1);
SQL> INSERT INTO LINEITEM VALUES('def',2);

SQL> UPDATE LINEITEM a
   SET a.l_manufacturer_name =
       (SELECT CASE
                 WHEN MOD(b.L_PARTKEY, 2) = 0 THEN
                  (SELECT M_NAME FROM MANUFACTURER m WHERE ROWNUM = 1)
                 WHEN MOD(b.L_PARTKEY, 2) = 1 THEN
                  (SELECT M_NAME
                     FROM (SELECT M_NAME, ROWNUM AS MYROW
                             FROM (SELECT M_NAME, ROWNUM FROM MANUFACTURER m))
                    WHERE MYROW = 2)
               END AS MANUFACTURER_NAME
          FROM LINEITEM b
         WHERE a.l_partkey = b.l_partkey);


ORA-01427: single-row subquery returns more than one row 


SQL> UPDATE LINEITEM a
   SET a.l_manufacturer_name =
       (SELECT CASE
                 WHEN MOD(max(b.L_PARTKEY), 2) = 0 THEN
                  (SELECT M_NAME FROM MANUFACTURER m WHERE ROWNUM = 1)
                 WHEN MOD(max(b.L_PARTKEY), 2) = 1 THEN
                  (SELECT M_NAME
                     FROM (SELECT M_NAME, ROWNUM AS MYROW
                             FROM (SELECT M_NAME, ROWNUM FROM MANUFACTURER m))
                    WHERE MYROW = 2)
               END AS MANUFACTURER_NAME
          FROM LINEITEM b
         WHERE a.l_partkey = b.l_partkey
         GROUP BY b.L_PARTKEY );

4 row updated.

It looks like you are using ROWNUM in the inner most query of your MOD(b.L_PARTKEY,2)=0 case.

The way ROWNUM works, is basically that it will get assigned to a row in a result after the WHERE clause has been evaluated.

This means that when you are refering to ROWNUM=1 in the WHERE clause, you are trying to compare it before it has been assigned.

In the other CASE with MOD(b.L_PARTKEY,2)=1 you have an inner select that returns a ROWNUM , you then refer to it with MYROW=2 outside that inner query. That works, because the ROWNUM has been assigned to each of the rows in that result by then.

You should consider doing the same for the first CASE as you do for the second:

UPDATE LINEITEM a 
  SET a.l_manufacturer_name = (
    SELECT
      CASE 
        WHEN MOD(b.L_PARTKEY,2)=0 
          THEN (
            SELECT
              M_NAME 
            FROM (
              SELECT 
                M_NAME, 
                ROWNUM AS MYROW 
              FROM (
                SELECT 
                  M_NAME, 
                  ROWNUM 
                FROM MANUFACTURER m
              )
            ) 
            WHERE 
              MYROW=1) 
        WHEN MOD(b.L_PARTKEY,2)=1 
          THEN (
            SELECT
              M_NAME 
            FROM (
              SELECT 
                M_NAME, 
                ROWNUM AS MYROW 
              FROM (
                SELECT 
                  M_NAME, 
                  ROWNUM 
                FROM MANUFACTURER m
              )
            ) 
            WHERE 
              MYROW=2) 
      END AS MANUFACTURER_NAME 
    FROM LINEITEM b 
    WHERE 
      a.l_partkey=b.l_partkey);

This should ensure that only one row is returned from either case, and your assignment should work.

thanks all. I realise my mistake. It's because there must be a primary key during the matching.

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