ORA-38101:INSERT VALUES条款中的无效列:

时间:2012-05-17 19:46:21

标签: sql oracle plsql

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

修改

好的,所以我在批量收集时发现了我的问题/解决方案。事实上,这就是我获取它的方式。我没有使用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%确定我的问题在于我如何尝试获取上面代码中显示的批量收集。所以我的问题是:我应该如何从批量集合中获取值以利用数据合并?

非常感谢您的建议或意见。谢谢。

1 个答案:

答案 0 :(得分: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而只是写{{} 1}}拉出了你要拉的所有数据。像

这样的东西
INSERT ... SELECT