【发布时间】:2017-07-12 10:28:44
【问题描述】:
我在 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_VAL20 和DATA_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 专家建议使用全局临时表 (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;
【问题讨论】:
-
不,GTT 不是对于所有会话都是通用的,它们的数据对于插入它的会话是私有的。
-
那么是这种情况下的最佳解决方案还是我们仍然可以使用对象类型?
-
我不知道。通过 PL/SQL 过程在 GTT 中创建的数据对通过不同会话连接的 Java 程序不可用。我对使用 Java 的了解还不够,无法说出是否会这样。
-
托尼谢谢,请不要考虑 Java。认为我必须在 SqlDeveloper 中本地运行它。我们可以使用 Object 来做到这一点吗?如果可能的话,您可以使用 Object 或使用 GTT 的任何伪代码发布解决方案吗?
-
重新更新 2:DBMS_SQL.EXECUTE_AND_FETCH 将只返回 1 行;您需要在循环中使用 DBMS_SQL.EXECUTE,然后使用 DBMS_SQL.FETCH_ROWS,直到没有更多行。
标签: oracle plsql execute-immediate global-temp-tables oracle-objects