【问题标题】:TYPE IS TABLE OF, from Oracle to PostgreSQLTYPE IS TABLE OF,从 Oracle 到 PostgreSQL
【发布时间】:2018-09-13 14:08:03
【问题描述】:

我目前正在将一些程序从 Oracle 迁移到 Postgres,这些程序使用的类型是为处理未知数量的值而创建的:

TYPE array_text IS TABLE OF VARCHAR2 (50);

所以他们可以声明如下变量:

myValues in array_text;

然后以这种方式使用它:

myValues(1) := 'VALUE1';
myValues(2) := 'VALUE2';
...

所以我一直在学习并尝试使用 Postgres 复制这种行为,但直到现在我都找不到正确的方法。我尝试创建一个复合类型,如:

CREATE TYPE array_text AS (
    val varchar(50)
);

或者

CREATE TYPE array_text AS (
    v varchar(50)[]
);

但是我不能像原来的那样使用它们,实际上我无法创建一个成功的测试。

我怎样才能得到这种行为或类似的东西?所以我可以设置和获取值,甚至可以像在 Oracle 中一样计算它的长度

【问题讨论】:

    标签: sql oracle postgresql plpgsql


    【解决方案1】:

    在 Postgres 中比在 Oracle 中简单得多 - 您不需要定义集合类型。只需声明一个数组。

    在 Postgres 中,TYPE array_text IS TABLE OF VARCHAR2 (50); 的合理且最有效的替换是 text[]

    要获取数组的长度,请使用cardinality()。您不需要特殊的方法来扩展其容量,只需为您想要的索引分配一个值。唯一的主要区别是,在 Postgres 中没有(简单的)方法可以收缩数组。

    declare
       myValues text[];
       num_values int;
    begin
    
      myValues[1] := 'VALUE1';
      myValues[2] := 'VALUE2';
    
      num_values := cardinality(myvalues); // yields 2
    
      myValues[3] := 'VALUE3';
      num_values := cardinality(myvalues); // yields 3
    end;
    

    扩展答案:您也可以使用类似的表格类型。因此,您不需要定义一个中间“表”集合类型,只需将表的类型用于数组。

    create table person
    (
      id integer,
      firstname text,
      lastname text
    );
    

    然后就可以使用了

    do
    $$
    declare
      people_list person[];
    begin
      people_list[1] := row(42, 'Arthur', 'Dent')::person;
      raise notice 'Name %', people_list[1].firstname;
    end;
    $$
    

    【讨论】:

    • Oracle 也有 CARDINALITY() function - 只是您也可以使用 myValues.COUNT,它似乎是更知名的 Oracle 解决方案。
    【解决方案2】:

    postgres 不允许包含未命名列的表(或复合类型)

    与表不同,数组可以是多维的,也可以从 [1] 或 [0] 以外的位置开始,因此您可能需要检查输入的格式是否正确(除非输入不正确 隐式导致错误)

    CREATE TYPE array_text AS (
        val varchar(50)[]
    );
    

    但是这会创建一个具有一个属性的复合类型,它是一个数组...所以您需要使用.val 来访问该数组。

    jasen=# do $$ 
    declare a array_text;
    begin 
       a.val[0]='won';
       a.val[1]='too';
       raise notice 'len=%',array_length(a.val,1); end;
    $$;
    NOTICE:  len=2
    DO
    

    但如果你声明数组内联,你可以只使用一个简单的名称。

    jasen=# do $$ 
    declare a varchar(50)[];
    begin 
       a[5]='eigh';
       a[6]='bee';
       raise notice 'len=%',array_length(a,1); end;
    $$;
    NOTICE:  len=2
    DO
    

    【讨论】:

    • 有了你的例子,我终于可以运行我的测试了,这次我将选择简单的数组方式,以避免从 Java 调用它们时的复杂性。
    猜你喜欢
    • 2022-12-27
    • 2022-12-27
    • 2018-11-16
    • 2015-12-19
    • 2019-11-19
    • 2021-04-15
    • 2022-11-20
    • 2022-11-18
    • 1970-01-01
    相关资源
    最近更新 更多