0

我在 Oracle 中创建了一个对象类型,如下所示:

CREATE OR REPLACE TYPE Generic_MDMU_Scrub_Cols_OBJ as Object 
( 
  i_strTypeOfEntry varchar2(50),
  ID_SCRUB number,
  NM_DATA_COL1 varchar2(50),
  NM_DATA_COL2 varchar2(50),
  NM_DATA_COL3 varchar2(50),
  NM_DATA_COL4 varchar2(50),
  NM_DATA_COL5 varchar2(50),
  NM_DATA_COL6 varchar2(50),
  NM_DATA_COL7 varchar2(50),
  NM_DATA_COL8 varchar2(50),
  NM_DATA_COL9 varchar2(50),
  NM_DATA_COL10 varchar2(50),
  NM_DATA_COL11 varchar2(50),
  NM_DATA_COL12 varchar2(50),
  NM_DATA_COL13 varchar2(50),
  NM_DATA_COL14 varchar2(50),
  NM_DATA_COL15 varchar2(50),
  NM_DATA_COL16 varchar2(50),
  NM_DATA_COL17 varchar2(50),
  NM_DATA_COL18 varchar2(50),
  NM_DATA_COL19 varchar2(50),
  NM_DATA_COL20 varchar2(50),
  DATA_VAL1 varchar2(50),
  DATA_VAL2 varchar2(50),
  DATA_VAL3 varchar2(50),
  DATA_VAL4 varchar2(50),
  DATA_VAL5 varchar2(50),
  DATA_VAL6 varchar2(50),
  DATA_VAL7 varchar2(50),
  DATA_VAL8 varchar2(50),
  DATA_VAL9 varchar2(50),
  DATA_VAL10 varchar2(50),
  DATA_VAL11 varchar2(50),
  DATA_VAL12 varchar2(50),
  DATA_VAL13 varchar2(50),
  DATA_VAL14 varchar2(50),
  DATA_VAL15 varchar2(50),
  DATA_VAL16 varchar2(50),
  DATA_VAL17 varchar2(50),
  DATA_VAL18 varchar2(50),
  DATA_VAL19 varchar2(50),
  DATA_VAL20 varchar2(50),
  OLD_DATA_VAL1 varchar2(50),
  OLD_DATA_VAL2 varchar2(50),
  OLD_DATA_VAL3 varchar2(50),
  OLD_DATA_VAL4 varchar2(50),
  OLD_DATA_VAL5 varchar2(50),
  OLD_DATA_VAL6 varchar2(50),
  OLD_DATA_VAL7 varchar2(50),
  OLD_DATA_VAL8 varchar2(50),
  OLD_DATA_VAL9 varchar2(50),
  OLD_DATA_VAL10 varchar2(50),
  OLD_DATA_VAL11 varchar2(50),
  OLD_DATA_VAL12 varchar2(50),
  OLD_DATA_VAL13 varchar2(50),
  OLD_DATA_VAL14 varchar2(50),
  OLD_DATA_VAL15 varchar2(50),
  OLD_DATA_VAL16 varchar2(50),
  OLD_DATA_VAL17 varchar2(50),
  OLD_DATA_VAL18 varchar2(50),
  OLD_DATA_VAL19 varchar2(50),
  OLD_DATA_VAL20 varchar2(50)
);
/  

现在我想编写一个过程,它将此对象类型作为输出参数返回给调用 Java 代码。基本上有几个表存储列,类似OLD_DATA_VAL1...OLD_DATA_VAL20DATA_VAL1...DATA_VAL120,另一个表具有列NM_DATA_COL1...NM_DATA_COL20,并且取决于各种用例,只有 3 或 5 个或任意数量的列将具有值,而其他列将为空。例如OLD_DATA_VAL1,OLD_DATA_VAL2,OLD_DATA_VAL3,DATA_VAL1,DATA_VAL2,DATA_VAL3,NM_DATA_COL1,NM_DATA_COL2,NM_DATA_COL3,有值和其他列为空。我创建了一个元表,它会给我逗号分隔的列名。

现在,当我尝试使用类型或游标时,问题是由于未填充所有值,因此会引发错误。我的程序是这样的:

create or replace PROCEDURE METADATA_AUTOMATION_MDPR (
    in_id_scrub IN NUMBER
)
AS
  V_COL_NAMES_CURRENT_SCRUB_DATA VARCHAR2(500);
  V_COL_NAMES_OLD_SCRUB_DATA VARCHAR2(500);
  V_COL_HEADER_MAP_WORKFLOW VARCHAR2(500);
  sqlstmt  VARCHAR2(2000);
  V_Generic_MDMU_Scrub_Cols Generic_MDMU_Scrub_Cols_OBJ;

SELECT COL_NAMES_CURRENT_SCRUB_DATA, COL_NAMES_OLD_SCRUB_DATA, COL_HEADER_MAP_WORKFLOW INTO V_COL_NAMES_CURRENT_SCRUB_DATA, V_COL_NAMES_OLD_SCRUB_DATA, V_COL_HEADER_MAP_WORKFLOW FROM MDDBO.MDMU_METADATA_AUTOMATION_MDTB WHERE ID_WORKFLOW_MAINTENANCE_MSTR = in_id_wf;
 DBMS_OUTPUT.PUT_LINE(V_COL_NAMES_CURRENT_SCRUB_DATA || ' --- ' || V_COL_NAMES_OLD_SCRUB_DATA || ' --- ' || V_COL_HEADER_MAP_WORKFLOW);

 sqlstmt:= 'select ' || V_COL_NAMES_CURRENT_SCRUB_DATA || ',' || V_COL_NAMES_OLD_SCRUB_DATA || ',' || V_COL_HEADER_MAP_WORKFLOW || ',AUTO.TYPE_OF_ENTRY i_strTypeOfEntry FROM MDDBO.MDMU_SCRUB_DATA_MDTB DATA, MDDBO.MDMU_SCRUB_LOG_MDTB MSTR, MDDBO.MDMU_MAP_WORK_FLOW_MDTB WKF,
 MDDBO.MDMU_METADATA_AUTOMATION_MDTB AUTO WHERE
 MSTR.ID_TBL = WKF.ID_WF and
 MSTR.id_scrub = :in_id_scrub and MSTR.id_scrub = DATA.id_scrub and
 AUTO.ID_WORKFLOW_MAINTENANCE_MSTR = WKF.ID_WF';

 DBMS_OUTPUT.PUT_LINE(sqlstmt);

 EXECUTE IMMEDIATE sqlstmt
  INTO V_Generic_MDMU_Scrub_Cols
  USING in_id_scrub;


 EXCEPTION
  WHEN OTHERS THEN
  DBMS_OUTPUT.PUT_LINE('error '||sqlerrm);

END METADATA_AUTOMATION_MDPR;

但它会在类型的情况下引发如下所示的 Oracle 错误 -

error ORA-00932: inconsistent datatypes: expected - got -

一些 Oracle Guy 建议使用 Global Temporary Table (GTT),但我相信它们在所有会话中都很常见,在这里不可行。所以,如果我想部分填充,但我不确定这是否是最好的情况,或者可以用对象完成一些事情,比如将未使用的值部分初始化为 null。

更新

从 2 个语句中打印 dbms_ouput 以使事情更清晰

输出1:

DATA_VAL1,DATA_VAL2,DATA_VAL3,DATA_VAL4,DATA_VAL5 --- OLD_DATA_VAL1,OLD_DATA_VAL2,OLD_DATA_VAL3,OLD_DATA_VAL4,OLD_DATA_VAL5 --- NM_DATA_COL1,NM_DATA_COL2,NM_DATA_COL3,NM_DATA_COL4,NM_DATA_COL5

输出2:

select DATA_VAL1,DATA_VAL2,DATA_VAL3,DATA_VAL4,DATA_VAL5,OLD_DATA_VAL1,OLD_DATA_VAL2,OLD_DATA_VAL3,OLD_DATA_VAL4,OLD_DATA_VAL5,NM_DATA_COL1,NM_DATA_COL2,NM_DATA_COL3,NM_DATA_COL4,NM_DATA_COL5,AUTO.TYPE_OF_ENTRY i_strTypeOfEntry FROM MDDBO.MDMU_SCRUB_DATA_MDTB DATA, MDDBO.MDMU_SCRUB_LOG_MDTB MSTR, MDDBO.MDMU_MAP_WORK_FLOW_MDTB WKF,
 MDDBO.MDMU_METADATA_AUTOMATION_MDTB AUTO WHERE
 MSTR.ID_TBL = WKF.ID_WF and
 MSTR.id_scrub = :in_id_scrub and MSTR.id_scrub = DATA.id_scrub and
 AUTO.ID_WORKFLOW_MAINTENANCE_MSTR = WKF.ID_WF

主要问题- 与对象类型中的列数相比,动态选择的列数更少。(见输出 1,每个也可以有 3 个)

更新 2

现在我主要关心的是如何从由可变数量的选定列形成的动态 sql 中获取值。

使用下面的查询我能够获得列标题,但不知何故无法获得 col 值。我的查询将只返回一行-

OPEN rc_ FOR sqlstmt using in_id_scrub;
   c_ := DBMS_SQL.to_cursor_number(rc_);
   DBMS_SQL.DESCRIBE_COLUMNS(c_, col_count_, desc_tab_);
   FOR i_ IN 1..col_count_ LOOP
      DBMS_OUTPUT.PUT_LINE(desc_tab_(i_).col_name);     
      DBMS_SQL.DEFINE_COLUMN(c_, i_, desc_tab_(i_).COL_NAME, 2000);
   END LOOP;
   res := DBMS_SQL.EXECUTE_AND_FETCH(c_, TRUE);
   --DBMS_OUTPUT.PUT_LINE(res);
   FOR i IN 1..col_count_ LOOP
        tab1.EXTEND;
        DBMS_SQL.COLUMN_VALUE(c_, i, tab1(tab1.LAST));
        --DBMS_SQL.COLUMN_VALUE(c_, i, tab1(i));
        --DBMS_SQL.COLUMN_VALUE(c_, i, arr1);
        --DBMS_OUTPUT.PUT_LINE(tab1(1));
   END LOOP;
   DBMS_SQL.CLOSE_CURSOR(c_);

  FOR l_row IN 1 .. tab1.COUNT
      LOOP
         DBMS_OUTPUT.put_line (tab1 (l_row));
      END LOOP;
4

1 回答 1

0

您在这里的具体问题似乎是这一行:

sqlstmt:= 'select ' || V_COL_NAMES_CURRENT_SCRUB_DATA || ',' || V_COL_NAMES_OLD_SCRUB_DATA || ',' || V_COL_HEADER_MAP_WORKFLOW || ',AUTO.TYPE_OF_ENTRY i_strTypeOfEntry FROM MDDBO.MDMU_SCRUB_DATA_MDTB DATA, MDDBO.MDMU_SCRUB_LOG_MDTB MSTR, MDDBO.MDMU_MAP_WORK_FLOW_MDTB WKF,
 MDDBO.MDMU_METADATA_AUTOMATION_MDTB AUTO WHERE
 MSTR.ID_TBL = WKF.ID_WF and
 MSTR.id_scrub = :in_id_scrub and MSTR.id_scrub = DATA.id_scrub and
 AUTO.ID_WORKFLOW_MAINTENANCE_MSTR = WKF.ID_WF';

...据我了解,因为例如 V_COL_NAMES_CURRENT_SCRUB_DATA 可能为空?

在这种情况下,一个简单的 NVL 就足够了:

sqlstmt:= 'select ' || NVL(V_COL_NAMES_CURRENT_SCRUB_DATA, 'null as col1') || ...

所以现在而不是:

select ,,SOMECOL,...

你会得到:

select null as col1, null as col2, SOMECOL, ...
于 2017-07-12T10:40:46.123 回答