INSERT ALL INTO 抛出 ORA-01722: 无效数字

INSERT ALL INTO throws ORA-01722: invalid number

我想将视图复制到 table。下面的过程抛出 ORA-01722:无效数字

BEGIN
   INSERT ALL
     INTO DB_LOCATIONS
      SELECT * FROM DB_LOCVIEW ; 
   COMMIT;
EXCEPTION
   WHEN OTHERS
   THEN
      BEGIN
         DBMS_OUTPUT.put_line  ('SQLCODE: ' || SQLCODE||'  -SQLERRM: '||SQLERRM);
      END;
END;

另一方面,如果我用 for 循环尝试,一切都很好:

DECLARE
    currow integer := 1;
BEGIN
    DBMS_OUTPUT.put_line ('starting.....');
    for xxinserteddata in (select * from DB_LOCVIEW )
    LOOP  
        BEGIN           
            DBMS_OUTPUT.put_line('currow: ' || currow);
            INSERT INTO DB_LOCATIONS ( 
                DB_DATE,
                LOCATIONID,
                MX_ET,
                MX_MT,
                BAND,
                SITE) 
            VALUES (  
                xxinserteddata.DB_DATE,
                xxinserteddata.LOCATIONID,
                xxinserteddata.MX_ET,
                xxinserteddata.MX_MT,
                xxinserteddata.BAND,
                xxinserteddata.SITE );
            currow := currow + 1;
        END;
    END LOOP;
    COMMIT;
    DBMS_OUTPUT.put_line ('end.');
EXCEPTION
   WHEN OTHERS
   THEN
      BEGIN
         DBMS_OUTPUT.put_line  ('-currow: ' || currow || '  -SQLCODE: ' || SQLCODE||'  -SQLERRM: '||SQLERRM);
      END;
END;

视图和 table 只有 5 个相同的列。知道为什么插入所有抛出异常吗?

编辑: 添加创建程序:

查看:

CREATE OR REPLACE FORCE VIEW DB_LOCVIEW ("LOCATIONID", "SITE", "MX_ET", "MX_MT", "DB_DATE", "BAND") AS 
      SELECT 
        l.LOCATIONID,
        l.SITE,
        l.MX_ET,
        l.MX_MT,
        l.CHANGE_DATE AS db_date,
        d.BAND
    FROM ALL_LOCATIONS l
    INNER JOIN LOC_DETATILS d ON (l.location = d.location)
    WHERE l.status = 'ACTIVE' ;

Table:

CREATE TABLE DB_LOCATIONS 
   (    "LOCATIONID" NUMBER, 
    "DB_DATE" DATE, 
    "MX_ET" NUMBER(10,2), 
    "MX_MT" NUMBER(10,2), 
    "SITE" VARCHAR2(8), 
    "BAND" NUMBER
   ) SEGMENT CREATION IMMEDIATE 
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "DB_DATA" ;

您没有在 INSERT ALL 语句中指定列的顺序,如果 table 的列顺序不同,那么您会发现使用 SELECT * 和未指定列将尝试将一个 table 中的列放入另一个 table.

中的错误列中

例如:

CREATE TABLE DB_LOCVIEW (DB_DATE, MX_ET, MX_MT, LOCATIONID, BAND, SITE) AS
SELECT SYSDATE, 'ABC', 'DEF', 1, 23, 'GHI' FROM DUAL;

-- Create the table with the columns in a different order
CREATE TABLE DB_LOCATIONS (DB_DATE, LOCATIONID, MX_ET, MX_MT, BAND, SITE) AS
SELECT DB_DATE, LOCATIONID, MX_ET, MX_MT, BAND, SITE FROM DB_LOCVIEW WHERE 1 = 0;

然后 运行 您的 INSERT ALL 查询失败并显示错误:

SQLCODE: -1722  -SQLERRM: ORA-01722: invalid number

这是因为该语句有效扩展为:

BEGIN
  INSERT ALL
    INTO DB_LOCATIONS (DB_DATE, LOCATIONID, MX_ET, MX_MT, BAND, SITE)
    SELECT DB_DATE, MX_ET, MX_MT, LOCATIONID, BAND, SITE FROM DB_LOCVIEW; 
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.put_line  ('SQLCODE: ' || SQLCODE||'  -SQLERRM: '||SQLERRM);
END;
/

而且您可以看到列不匹配。因此,即使列具有相同的类型,列的顺序也很重要。


相反,您可以指定列及其顺序:

BEGIN
  INSERT ALL
    INTO DB_LOCATIONS (DB_DATE, MX_ET, MX_MT, LOCATIONID, BAND, SITE)
    SELECT DB_DATE, MX_ET, MX_MT, LOCATIONID, BAND, SITE FROM DB_LOCVIEW; 
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.put_line  ('SQLCODE: ' || SQLCODE||'  -SQLERRM: '||SQLERRM);
END;
/

或使用 INSERT INTO ... SELECT 并指定列:

BEGIN
   INSERT INTO DB_LOCATIONS (DB_DATE, LOCATIONID, MX_ET, MX_MT, BAND, SITE)
   SELECT DB_DATE, LOCATIONID, MX_ET, MX_MT, BAND, SITE FROM DB_LOCVIEW;
   COMMIT;
EXCEPTION
   WHEN OTHERS THEN
     DBMS_OUTPUT.put_line  ('SQLCODE: ' || SQLCODE||'  -SQLERRM: '||SQLERRM);
END;
/

注意:您不需要捕获异常;如果出现错误,它将停止 PL/SQL 块,隐式回滚事务并打印错误跟踪。此外,捕获 OTHERS 被认为是不好的做法。如果你确实想捕获异常,那么你应该捕获特定的预期异常,然后你知道什么时候有未捕获的异常发生了意想不到的事情,你可以调试它;如果您捕捉到所有异常,那么您将失去识别意外行为的能力。

或者,没有 PL/SQL:

INSERT INTO DB_LOCATIONS (DB_DATE, LOCATIONID, MX_ET, MX_MT, BAND, SITE)
SELECT DB_DATE, LOCATIONID, MX_ET, MX_MT, BAND, SITE FROM DB_LOCVIEW;

COMMIT;

db<>fiddle here