0

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

编辑:

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

非常感谢您提出建议或意见。谢谢你。

4

1 回答 1

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也会有问题——a 的源和目标是同一个表是没有意义的——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要从空开始,听起来你最好不要使用 a MERGE,不要使用 a 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
于 2012-05-17T20:37:24.090 回答