ORA-38101: INSERT VALUES 子句中的列无效:

Posted

技术标签:

【中文标题】ORA-38101: INSERT VALUES 子句中的列无效:【英文标题】:ORA-38101: Invalid column in the INSERT VALUES Clause: 【发布时间】:2012-05-17 19:46:20 【问题描述】:

因此,我正在通过创建一个工具来对数据进行去规范化以进行比较,从而测试我的规范化数据的准确性。在这样做的同时,我正在研究这个工具的新技术,而不是我通常会做的事情(使用游标并循环插入/更新)所以我遇到了两个我想尝试的项目,它们是批量集合和合并语句.我的问题是我在寻找利用批量收集的最佳方式时遇到了一些麻烦。

编辑:

好的,所以我在批量收集时找到了我的问题/解决方案。这实际上是我获取它的方式。我没有使用 forall 语句,而是将其更改为 for 并在其下方添加了一个循环。这导致发现更多错误。我试图调用存储在 indx 中的值的方式是错误的,所以我已经纠正了。现在我似乎遇到的唯一问题是标题中提到的错误。由于某种原因,在我的合并中,我尝试在插入中使用的第一个值会引发以下错误:

PL/SQL:ORA-38101:INSERT VALUES 子句中的列无效:“TMI”.“MACHINE_INTERVAL_ID” ORA-06550:第 92 行,第 7 列:

所以我现在想知道的是为什么我会收到这个错误。我理解我的插入值无效的概念。但我不完全明白为什么会这样。

这是有问题的合并语句:

MERGE INTO TEST_MACHINE_INTERVAL TMI
      USING (SELECT * FROM TEST_MACHINE_INTERVAL) OTMI
      ON (TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID)
      WHEN MATCHED THEN
        UPDATE SET  TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME = OTMI.START_DATE_TIME,
                    TMI.INTERVAL_DURATION = OTMI.INTERVAL_DURATION,  TMI.CALC_END_TIME = OTMI.CALC_END_TIME, 
                    TMI.MACHINE_NAME = OTMI.MACHINE_NAME, TMI.SITE_NAME = OTMI.SITE_NAME, 
                    TMI.OPERATOR_INSTANCE = OTMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2 = OTMI.OPERATOR_INSTANCE2,
                    TMI.OPERATOR_INSTANCE3 = OTMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME = OTMI.SHIFT_NAME,
                    TMI.INTERVAL_CATEGORY = OTMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME = OTMI.NTP_CATEGORY_NAME,
                    TMI.MACHINE_MODE = OTMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME = OTMI.JOB_LOAD_STATE_NAME,
                    TMI.RAW_SOURCE_MSG_TYPE = OTMI.RAW_SOURCE_MSG_TYPE  
       WHEN NOT MATCHED THEN
        INSERT (TMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME, TMI.INTERVAL_DURATION, TMI.CALC_END_TIME, 
                TMI.MACHINE_NAME, TMI.SITE_NAME, TMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2,
                TMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME, TMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME,
                TMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME, TMI.RAW_SOURCE_MSG_TYPE )
        VALUES (MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION, CALC_END_TIME, 
                MACHINE_NAME, SITE_NAME, OPERATOR_INSTANCE, OPERATOR_INSTANCE2, OPERATOR_INSTANCE3,
                SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME, MACHINE_MODE,
                JOB_LOAD_STATE_NAME, RAW_SOURCE_MSG_TYPE);

下面是我新修改的代码的完整版:

-- Denormaliztion of machine_interval Table.
-- Is used to take all intervals from interval_table and convert it from 
-- foreign keys to corresponding names.
DECLARE

START_DATE_TIME TIMESTAMP(6) WITH TIME ZONE;
CALC_END_TIME TIMESTAMP(6) WITH TIME ZONE;
MACHINE_NAME VARCHAR2(256);
SITE_NAME VARCHAR2(256);
OPERATOR_INSTANCE VARCHAR2(256);
OPERATOR_INSTANCE2 VARCHAR2(256);
OPERATOR_INSTANCE3 VARCHAR2(256);
SHIFT_NAME VARCHAR2(256);
INTERVAL_CATEGORY VARCHAR2(256);
NPT_CATEGORY_NAME VARCHAR2(256);
MACHINE_MODE VARCHAR2(256);
JOB_LOAD_STATE_NAME VARCHAR2(256);
RAW_SOURCE_MSG_TYPE VARCHAR2(256);
INTERVAL_DURATION NUMBER;
MACHINE_INTERVAL_ID NUMBER;

--step one: Get all the intervals and store them into a cursor
CURSOR INTERVAL_CUR IS 
SELECT * 
FROM MACHINE_INTERVAL 
ORDER BY START_DATE_TIME ASC;

TYPE TOTAL_MACHINE_INTERVALS IS
TABLE OF interval_cur%rowtype
INDEX BY PLS_INTEGER;

MACHINE_INTERVAL_ROW TOTAL_MACHINE_INTERVALS;

BEGIN 
--step two: Make sure Test_Machine_interval is empty.
  DELETE FROM TEST_MACHINE_INTERVAL;

  OPEN INTERVAL_CUR;
  LOOP
    FETCH INTERVAL_CUR BULK COLLECT INTO MACHINE_INTERVAL_ROW LIMIT 100;
--step three: Loop through all the intervals. 
    FOR INDX IN 1..MACHINE_INTERVAL_ROW.COUNT 
    LOOP
--step four: Gather all datavalues needed to populate test_machine_interval. 

      MACHINE_INTERVAL_ID := MACHINE_INTERVAL_ROW(indx).MACHINE_INTERVAL_ID;
      START_DATE_TIME := MACHINE_INTERVAL_ROW(indx).START_DATE_TIME;
      CALC_END_TIME := MACHINE_INTERVAL_ROW(indx).CALC_END_TIME;
      INTERVAL_DURATION := MACHINE_INTERVAL_ROW(indx).INTERVAL_DURATION;
      INTERVAL_CATEGORY := MACHINE_INTERVAL_ROW(indx).INTERVAL_CATEGORY;
      RAW_SOURCE_MSG_TYPE := MACHINE_INTERVAL_ROW(indx).RAW_SOURCE_MSG_TYPE;

      SELECT M.MACHINE_NAME INTO MACHINE_NAME 
      FROM MACHINE M  
      WHERE MACHINE_ID = MACHINE_INTERVAL_ROW(indx).MACHINE_ID; 

      SELECT S.SITE_NAME INTO SITE_NAME 
      FROM SITE S  
      LEFT OUTER JOIN MACHINE M ON M.SITE_ID = S.SITE_ID 
      WHERE M.MACHINE_ID = MACHINE_INTERVAL_ROW(indx).MACHINE_ID;  

      SELECT O.OPERATOR_NAME INTO OPERATOR_INSTANCE 
      FROM OPERATOR_INSTANCE OI  
      LEFT OUTER JOIN OPERATOR O ON OI.OPERATOR_ID = O.OPERATOR_ID
      WHERE OI.OPERATOR_INSTANCE_ID = MACHINE_INTERVAL_ROW(indx).OPERATOR_INSTANCE_ID; 

      SELECT O.OPERATOR_NAME INTO OPERATOR_INSTANCE2 
      FROM OPERATOR_INSTANCE OI  
      LEFT OUTER JOIN OPERATOR O ON OI.OPERATOR_ID = O.OPERATOR_ID
      WHERE OI.OPERATOR_INSTANCE_ID = MACHINE_INTERVAL_ROW(indx).OPERATOR_INSTANCE_ID_2; 

      SELECT O.OPERATOR_NAME INTO OPERATOR_INSTANCE3 
      FROM OPERATOR_INSTANCE OI  
      LEFT OUTER JOIN OPERATOR O ON OI.OPERATOR_ID = O.OPERATOR_ID
      WHERE OI.OPERATOR_INSTANCE_ID = MACHINE_INTERVAL_ROW(indx).OPERATOR_INSTANCE_ID_3; 

      SELECT NPT_CATEGORY_NAME INTO NPT_CATEGORY_NAME 
      FROM NPT_CATEGORY 
      WHERE NPT_CATEGORY_ID = MACHINE_INTERVAL_ROW(indx).NPT_CATEGORY_ID;

      SELECT S.SHIFT_NAME INTO SHIFT_NAME
      FROM SHIFTS S  
      LEFT OUTER JOIN SHIFT_TBL STBL ON S.SHIFT_ID = STBL.SHIFT_NAME_FK 
      WHERE STBL.SHIFT_ID_PK = MACHINE_INTERVAL_ROW(indx).SHIFT_ID; 

      SELECT MACHINE_MODE_NAME INTO MACHINE_MODE 
      FROM MACHINE_MODE MM 
      WHERE MM.MACHINE_MODE_ID = MACHINE_INTERVAL_ROW(indx).MACHINE_MODE_ID;

      SELECT JLS.JOB_LOAD_STATE_NAME INTO JOB_LOAD_STATE_NAME 
      FROM JOB_LOAD_STATE JLS 
      WHERE JLS.JOB_LOAD_STATE_ID = MACHINE_INTERVAL_ROW(indx).JOB_LOAD_STATE_ID;

    --step five: merge record into test_machine_interval.
      MERGE INTO TEST_MACHINE_INTERVAL TMI
      USING (SELECT * FROM TEST_MACHINE_INTERVAL) OTMI
      ON (TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID)
      WHEN MATCHED THEN
        UPDATE SET  TMI.MACHINE_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME = OTMI.START_DATE_TIME,
                    TMI.INTERVAL_DURATION = OTMI.INTERVAL_DURATION,  TMI.CALC_END_TIME = OTMI.CALC_END_TIME, 
                    TMI.MACHINE_NAME = OTMI.MACHINE_NAME, TMI.SITE_NAME = OTMI.SITE_NAME, 
                    TMI.OPERATOR_INSTANCE = OTMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2 = OTMI.OPERATOR_INSTANCE2,
                    TMI.OPERATOR_INSTANCE3 = OTMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME = OTMI.SHIFT_NAME,
                    TMI.INTERVAL_CATEGORY = OTMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME = OTMI.NTP_CATEGORY_NAME,
                    TMI.MACHINE_MODE = OTMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME = OTMI.JOB_LOAD_STATE_NAME,
                    TMI.RAW_SOURCE_MSG_TYPE = OTMI.RAW_SOURCE_MSG_TYPE  
       WHEN NOT MATCHED THEN
        INSERT (TMI.MACHINE_INTERVAL_ID, TMI.START_DATE_TIME, TMI.INTERVAL_DURATION, TMI.CALC_END_TIME, 
                TMI.MACHINE_NAME, TMI.SITE_NAME, TMI.OPERATOR_INSTANCE, TMI.OPERATOR_INSTANCE2,
                TMI.OPERATOR_INSTANCE3, TMI.SHIFT_NAME, TMI.INTERVAL_CATEGORY, TMI.NTP_CATEGORY_NAME,
                TMI.MACHINE_MODE, TMI.JOB_LOAD_STATE_NAME, TMI.RAW_SOURCE_MSG_TYPE )
        VALUES (MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION, CALC_END_TIME, 
                MACHINE_NAME, SITE_NAME, OPERATOR_INSTANCE, OPERATOR_INSTANCE2, OPERATOR_INSTANCE3,
                SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME, MACHINE_MODE,
                JOB_LOAD_STATE_NAME, RAW_SOURCE_MSG_TYPE);

    /*
      EXECUTE IMMEDIATE 'INSERT INTO TEST_MACHINE_INTERVAL
                                           (MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION, CALC_END_TIME, 
                                            MACHINE_NAME, SITE_NAME, OPERATOR_INSTANCE, OPERATOR_INSTANCE2,
                                            OPERATOR_INSTANCE3, SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME,
                                            MACHINE_MODE,JOB_LOAD_STATE_NAME,RAW_SOURCE_MSG_TYPE )
                                     VALUES(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15)' 
                                     USING  MACHINE_INTERVAL_ID, START_DATE_TIME, INTERVAL_DURATION,
                                            CALC_END_TIME, MACHINE_NAME, SITE_NAME, 
                                            OPERATOR_INSTANCE, OPERATOR_INSTANCE2, OPERATOR_INSTANCE3,
                                            SHIFT_NAME, INTERVAL_CATEGORY, NTP_CATEGORY_NAME,
                                            MACHINE_MODE,JOB_LOAD_STATE_NAME,RAW_SOURCE_MSG_TYPE;
     */
    END LOOP;
  EXIT WHEN MACHINE_INTERVAL_ROW.COUNT = 0; 
END LOOP;
END;

我 75% 确定我的问题在于我如何尝试获取上面代码中显示的批量集合。所以我的问题是:我应该如何从批量集合中获取值以用于数据合并?

非常感谢您的建议或 cmets。谢谢。

【问题讨论】:

【参考方案1】: 如果您使用FORALL,则需要遵循一条SQL 语句,您将把整个集合传递给该语句。如果您只是想遍历集合中的元素,您可以使用FOR 循环。 引用集合的第 n 个元素的语法是 collection_name(index).column_name

所以,如果你想逐个迭代集合中的元素,你会想要类似

FOR indx IN MACHINE_INTERVAL_ROW.FIRST..MACHINE_INTERVAL_ROW.COUNT 
LOOP
  MACHINE_INTERVAL_ID := machine_interval_row(indx).MACHINE_INTERVAL_ID;
  START_DATE_TIME     := machine_interval_row(indx).START_DATE_TIME;

  <<more code>>
END LOOP;

但是,如果您要重构代码,我不确定使用局部变量 MACHINE_INTERVAL_ID 而不是仅使用 machine_interval_row(indx).MACHINE_INTERVAL_ID 会带来什么好处。我也不确定你为什么要执行六个单独的 SELECT 语句,每个语句都返回一行,而不是编写一个 SELECT 语句将所有这些表连接在一起并填充你想要的任何局部变量。

您的MERGE 也会有问题——MERGE 的源和目标是同一个表是没有意义的——我希望您收到 Oracle 的错误如果它试图执行该语句,则无法生成一组稳定的行。您可以将查询的源更改为针对 DUAL 的查询,该查询选择了您填充的所有局部变量,我猜,即

  MERGE INTO TEST_MACHINE_INTERVAL TMI
  USING (SELECT machine_interval_row(indx).MACHINE_INTERVAL_ID,
                machine_interval_row(indx).START_DATE_TIME
           FROM dual) OTMI
  ON (TMI.MACHIN_INTERVAL_ID = OTMI.MACHINE_INTERVAL_ID)

如果TEST_MACHINE_INTERVAL 一开始是空的,听起来你最好不要使用MERGE,不要使用BULK COLLECT,而只是写一个INSERT ... SELECT 来提取所有数据你想拉。类似的东西

INSERT INTO test_machine_interval( machine_interval_id,
                                   start_date_time,
                                   <<more columns>> )
  SELECT machine_interval_id,
         last_value(start_date_time) over (partition by machine_interval_id
                                               order by start_date_time asc
                                           rows between unbounded preceding 
                                                    and unbounded following ) last_start_date_time,
         <<more columns>>
    FROM machine_interval

【讨论】:

生成一个选择语句然后插入结果是这个工具的原始版本。我正在使用批量收集/合并作为学习如何在实际练习中使用它们的一种方式,但是在阅读了您的回复并回顾了我要离开的示例之后,我现在看到他们在合并中使用了 2 个表.由于他们使用相似的表名,我猜我一定错过了。

以上是关于ORA-38101: INSERT VALUES 子句中的列无效:的主要内容,如果未能解决你的问题,请参考以下文章

多个 INSERT 语句与具有多个 VALUES 的单个 INSERT

MySQL insert set 和 insert values

MySQL - 结合 INSERT、VALUES 和 SELECT?

Oracle中以insert values的形式同时插入多条记录

如何用insert into values插入多条数据

Mariadb中同时使用with和insert ... values