将引用集合表的过程从 Oracle 转换为 Postgresql 时出错
Posted
技术标签:
【中文标题】将引用集合表的过程从 Oracle 转换为 Postgresql 时出错【英文标题】:Error while converting a procedure referring to a table of collections from Oracle to Postgresql 【发布时间】:2018-08-20 17:27:12 【问题描述】:我在 Oracle 11.2.0.4 上,需要将数据库过程转换为 Postgresql 9.6。我有 Amazon SCT 工具,但它在一些特定情况下会出错。我正在研究的是一个 pl/sql 过程,它的输入类型是对象类型的集合。代码如下,转换时出错。任何关于我如何去做的建议,我都会非常感激。转换时的错误是由于这一行
select count(*) INTO v_cnt from TABLE(t_cust_tab_type_i);
:
create or replace type temp_n_cust_header_type
is
object(ssn number,
fname varchar2(20),
lname varchar2(20),
items varchar2(100));
/
pause ;
create or REPLACE type temp_n_customer_tab_type is table of temp_n_cust_header_type;
/
pause;
CREATE OR REPLACE PROCEDURE temp_n_ins_cust_proc (
p_cust_tab_type_i IN temp_n_customer_tab_type)
IS
t_cust_tab_type_i temp_n_customer_tab_type;
v_cnt number;
BEGIN
t_cust_tab_type_i := temp_n_customer_tab_type();
select count(*) INTO v_cnt from TABLE(t_cust_tab_type_i);
DBMS_OUTPUT.put_line (
'there are '
||v_cnt
/* || p_cust_tab_type_i.COUNT */
|| ' elements in the collection');
FOR i IN 1 .. p_cust_tab_type_i.COUNT
LOOP
DBMS_OUTPUT.put_line (
'ssn(' || i || ') = ' || p_cust_tab_type_i (i).ssn);
END LOOP;
END;
/
谢谢, 尼拉夫
这是我在 postgresql 中的内容:
CREATE TYPE temp_n_cust_header_type AS (
ssn DOUBLE PRECISION,
fname CHARACTER VARYING(20),
lname CHARACTER VARYING(20),
items CHARACTER VARYING(100)
);
CREATE TYPE temp_n_customer_tab_type AS (
col1 temp_n_cust_header_type[]
);
CREATE OR REPLACE FUNCTION temp_n_ins_cust_proc(IN p_cust_tab_type_i temp_n_customer_tab_type)
RETURNS void
AS
$BODY$
DECLARE
t_cust_tab_type_i temp_n_customer_tab_type;
v_cnt DOUBLE PRECISION;
BEGIN
t_cust_tab_type_i := ARRAY[]
/*
[9996 - Severity CRITICAL - Transformer error occurred. Please submit report to developers.]
select count(*) INTO v_cnt from TABLE(t_cust_tab_type_i)
*/;
RAISE DEBUG USING MESSAGE := CONCAT_WS('', 'there are ', v_cnt
/* || p_cust_tab_type_i.COUNT */, ' elements in the collection');
FOR i IN 1..array_length(p_cust_tab_type_i, 1) LOOP
RAISE DEBUG USING MESSAGE := CONCAT_WS('', 'ssn(', i, ') = ', p_cust_tab_type_i[i].ssn);
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
【问题讨论】:
在将此过程 temp_n_ins_cust_proc 转换为 Postgresql 时从 Amazon SCT 得到的错误是:/* [9996 - Severity CRITICAL - Transformer 发生错误。请向开发者提交报告。] select count(*) INTO v_cnt from TABLE(t_cust_tab_type_i) */ 请向我们展示您的 Postgres 代码 - 会引发错误的代码。在 Postgres 中替换 Oracle 集合的常用方法是使用数组。 edit 你的问题。 不在 cmets 中发布代码 谢谢我已经编辑了这个问题并发布了我在 postgresql 中的内容。请注意,我没有编写 postgresql 代码,但它是由 amazon sct 工具生成的。我不知道如何编写可以满足此需求的代码,因此需要帮助。谢谢。 【参考方案1】:您不能像表格一样使用数组。要获取传递数组的长度,请使用cardinality
或array_length()
。
另外:temp_n_customer_tab_type
是具有单个属性的类型,即数组。属性col1
是一个数组,而不是整个“事物”。您需要使用cardinality(t_cust_tab_type_i.col1)
,而不是cardinality(t_cust_tab_type_i)
。
不需要中间类型temp_n_customer_tab_type
,可以直接将一个类型的数组传递给函数。
您还检查了初始化为空数组的局部变量 t_cust_tab_type_i
的长度 - 因此结果(如果有效)将始终为零开始。我不确定你想在那里做什么。
最好使用format()
函数将变量放入字符串中(而不是concat()
或concat_ws()
。它使代码更具可读性。
所以把所有这些放在一起,你就会得到像他这样的东西。
CREATE TYPE temp_n_cust_header_type AS (
ssn integer,
fname CHARACTER VARYING(20),
lname CHARACTER VARYING(20),
items CHARACTER VARYING(100)
);
CREATE OR REPLACE FUNCTION temp_n_ins_cust_proc(IN p_cust_tab_type_i temp_n_cust_header_type[])
RETURNS void
AS
$BODY$
DECLARE
t_cust_tab_type_i temp_n_cust_header_type[];
v_cnt integer; -- no need for a "double" to hold a count
BEGIN
t_cust_tab_type_i := ARRAY[];
-- this will always be zero
v_cnt := cardinality(t_cust_tab_type_i);
RAISE DEBUG USING MESSAGE := format('there are %s elements in the collection', v_cnt);
FOR i IN 1..cardinality(p_cust_tab_type_i) LOOP
RAISE DEBUG USING MESSAGE := format('ssn(%s)=%s', i, p_cust_tab_type_i[i].ssn);
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
您还应该避免使用double precision
数据类型——尤其是在您不需要小数的情况下。对于没有小数的数字,请使用 integer
或 bigint
。和numeric
用于应该有小数位数的数字。
我不推荐以下方法,但模拟select .. from table()
事物的复杂而缓慢的方法是:
select count(*)
into v_cnt
from unnest(t_cust_tab_type_i);
但这是不必要的复杂和缓慢。使用cardinality()
会好很多。
您最初的初始化t_cust_tab_type_i := ARRAY[];
也不正确,因为声明的变量类型不是数组,而是具有单个属性的自定义类型。应该是这样的:t_cust_tab_type_i := row(''::temp_n_cust_header_type[]);
使用数组的单个属性初始化记录类型的正确方法
【讨论】:
太棒了!!!非常感谢这么详细的指导。我会审查,我想这应该是它。如果我被困在某个地方,我会进一步更新,再次非常感谢。 @dbusern:一旦你有答案,就不要改变你原来的问题。如果这解决了您最初的问题,请接受此答案,如果您有新问题,请提出新问题。 是的!我的问题已经完全回答了。非常感谢你!!以上是关于将引用集合表的过程从 Oracle 转换为 Postgresql 时出错的主要内容,如果未能解决你的问题,请参考以下文章
将 SQL Server 存储过程转换为 Oracle 过程以从表中查询