0

我在 Oracle 11.2.0.4 上,需要将数据库过程转换为 Postgresql 9.6。我有 Amazon SCT 工具,但它在一些特定情况下会出错。我正在研究的是一个 pl/sql 过程,该过程具有输入类型作为对象类型的集合。代码如下,转换时出错。任何关于我如何去做的建议,我都会非常感激。转换时的错误是由于这一行

select count(*) INTO v_cnt from TABLE(t_cust_tab_type_i) ; <- 似乎 postgresql 没有嵌套类型或集合的集合,因此可能会出现此错误-不确定我刚开始使用 postgresql,并且我没有很多知识。

    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;
4

1 回答 1

2

您不能使用像表格这样的数组。要获取传递数组的长度,请使用cardinalityor 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()or 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数据类型 - 特别是如果您不需要小数。使用integerorbigint表示没有小数的数字。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[]);

使用数组的单个属性初始化记录类型的正确方法

于 2018-08-20T18:33:37.677 回答