ORACLE:插入对象类型集合的表值

Posted

技术标签:

【中文标题】ORACLE:插入对象类型集合的表值【英文标题】:ORACLE: INSERT INTO Table VALUES of object type collection 【发布时间】:2016-03-20 10:17:45 【问题描述】:

已创建以下类型;

CREATE OR REPLACE TYPE OBJ_TYPE AS OBJECT
  ( FLAG      DATE
  , NUMB      NUMBER(2,0)
  , VARC      VARCHAR2(40 BYTE));
/
CREATE OR REPLACE TYPE TBL_OBJ_TYPE AS TABLE OF OBJ_TYPE;
/

我想简单地将数据集插入到表中;

DECLARE
  DATA_SET TBL_OBJ_TYPE := TBL_OBJ_TYPE();
BEGIN
  FOR REC IN (SELECT * FROM TBL_01)
  LOOP
    DATA_SET.EXTEND;
    DATA_SET(DATA_SET.COUNT) :=
    OBJ_TYPE( 1
            , REC.TBL_01_COL1
            , REC.TBL_01_COL2);
  END LOOP;

  FORALL REC IN DATA_SET.FIRST..DATA_SET.LAST
    INSERT INTO TBL_02 
    VALUES ( DATA_SET(REC).FLAG --listed column
           , DATA_SET(REC).NUMB --listed column
           , DATA_SET(REC).VARC); --listed column
END;

这个工作正常,但是否有可能更改“VALUES”子句以避免命名源对象中的每个属性?我想要这样的东西:

VALUES DATA_SET(REC)

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

我们可以使用对象类型定义创建表:

SQL> create table TBL_02 of OBJ_TYPE
  2  /

Table created.

SQL> 

这样做的充分理由并不多,但我们可以使用程序中的类型。

这里是一个小例子,从测试数据开始

SQL> select * from tbl_01
  2  /

     COL_1 COL_2
---------- ----------------------------------------
        23 ABC
        42 XYZ

SQL> DECLARE
  2     DATA_SET TBL_OBJ_TYPE := TBL_OBJ_TYPE();
  3  BEGIN
  4     FOR REC IN (SELECT * FROM TBL_01)
  5     LOOP
  6      DATA_SET.EXTEND;
  7      DATA_SET(DATA_SET.COUNT) :=
  8      OBJ_TYPE( sysdate
  9              , REC.COL_1
 10               , REC.COL_2);
 11     END LOOP;
 12
 13      FORALL REC IN DATA_SET.FIRST..DATA_SET.LAST
 14        INSERT INTO TBL_02 
 15        VALUES DATA_SET(REC)
 16        ; 
 17  END;
 18  /    

PL/SQL procedure successfully completed.

SQL> select * from tbl_02;

FLAG            NUMB VARC
--------- ---------- ----------------------------------------
20-MAR-16         23 ABC
20-MAR-16         42 XYZ

SQL> 

或者,我们可以使用针对目标表定义的 PL/SQL 对象。这对 TBL_02 使用常规堆表:

DECLARE
  type tgt_nt is table of TBL_02%rowtype;
  data_set tgt_nt;
BEGIN
  SELECT sysdate, COL_1, COL_2 
  bulk collect into data_set
  FROM TBL_01;

  FORALL REC IN DATA_SET.FIRST..DATA_SET.LAST
    INSERT INTO TBL_02 
    VALUES DATA_SET(REC)
    ; 
END;
/

【讨论】:

【参考方案2】:

假设表 TBL_01 中的列与对象声明中的名称相同:

DECLARE
  DATA_SET TBL_OBJ_TYPE := TBL_OBJ_TYPE();
BEGIN
    SELECT OBJ_TYPE( sysdate, numb, varc )  BULK COLLECT INTO  DATA_SET
    FROM TBL_01;

    INSERT INTO TBL_02( flag, numb, varc )
    SELECT * FROM Table( DATA_SET );
END;
/

如果TBL_01 列有不同的名称,例如 X、Y、Z,则分别更改此行:SELECT OBJ_TYPE( X, Y, Z ) BULK COLLECT ...


注意:您不能将1 分配到此处的第一个字段:

OBJ_TYPE( 1
        , REC.TBL_01_COL1
        , REC.TBL_01_COL2);

因为第一个字段FLAG 在对象声明中被声明为date 类型。 在我的示例中,我已将 1 替换为 sysdate

【讨论】:

您好 kordirko,您显然是正确的 sysdate,只是忘记更改。但是无论如何,有什么方法可以遵循我提到的内容吗? FORALL + INSERT INTO table VALUES --> 带有集合而不指定每个列名,而不是使用 SELECT 子句?【参考方案3】:
--Rollbaclk--

DROP TYPE TBL_OBJ_TYPE;
DROP TYPE OBJ_TYPE;
DROP TABLE TBL_02;
DROP TABLE TBL_01;

--execute--

CREATE OR REPLACE TYPE OBJ_TYPE AS OBJECT
(
   FLAG DATE,
   NUMB NUMBER (2, 0),
   VARC VARCHAR2 (40 BYTE)
);
/

CREATE OR REPLACE TYPE TBL_OBJ_TYPE AS TABLE OF OBJ_TYPE;
/

CREATE TABLE TBL_02
(
   FLAG   DATE,
   NUMB   NUMBER (2, 0),
   VARC   VARCHAR2 (40 BYTE)
);


CREATE TABLE TBL_01
(
   TBL_01_COL0   DATE,
   TBL_01_COL1   NUMBER (2, 0),
   TBL_01_COL2   VARCHAR2 (40 BYTE)
);


INSERT INTO TBL_01
     VALUES (SYSDATE, 1, 'mohit');


INSERT INTO TBL_01
     VALUES (SYSDATE, 2, 'vijay');


INSERT INTO TBL_01
     VALUES (SYSDATE, 3, 'sohan');

COMMIT;


SELECT * FROM TBL_01;


DECLARE
   DATA_SET   TBL_OBJ_TYPE := TBL_OBJ_TYPE ();
BEGIN
   FOR REC IN (SELECT * FROM TBL_01)
   LOOP
      DATA_SET.EXTEND;
      DATA_SET (DATA_SET.COUNT) :=
         OBJ_TYPE (REC.TBL_01_COL0, REC.TBL_01_COL1, REC.TBL_01_COL2);
   END LOOP;

   FORALL REC IN DATA_SET.FIRST .. DATA_SET.LAST
      INSERT INTO TBL_02
              VALUES (
                        DATA_SET (REC).FLAG,
                        DATA_SET (REC).NUMB,
                        DATA_SET (REC).VARC);
END;

SELECT * FROM TBL_02;

【讨论】:

以上是关于ORACLE:插入对象类型集合的表值的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle 12c 中插入对象数据

从集合类型 oracle 12c 插入表 - ORA-00902:无效数据类型

在 Oracle 中对集合类型“对象”进行批量收集

在 SQL 中创建和更改表值函数时对象类型不兼容

如何将对象(模型类型对象)插入到 Laravel 中特定索引号的集合对象中?

如何将 .NET 对象集合(父子)层次结构传递给 SQL Server 存储过程