postgresql 如何在PL/pgSQL中查询自定义数据类型数组中的自定义数据类型对象?

px9o7tmv  于 2022-11-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(687)

假设我有:CREATE TYPE compfoo AS (f1 int, f2 text);我创建了一个表foo,它包含两列:foid和fooname,对应于compfoo的字段,稍后我插入了一些记录1, aa2, bb3, cc
然后,我定义了一个PL/pgSQL函数(大致如下所示:)

create or replace function foo_query()
returns text
language plpgsql
as $$
    declare
      r compfoo;
      arr compfoo [];
      footemp compfoo;
      result text;
    begin
      for r in
        select * from foo where fooid = 1 OR fooid = 2
        loop
        arr := array_append(arr, r);
      end loop;
      foreach footemp in array arr
        loop
        select footemp.f1 into result where footemp.f1 = 1;
      end loop;
    return result;
    end;
$$

在这里,我首先通过列名查询foo,并将结果保存到arr(compfoo的数组)中。随后,我遍历arr,并尝试通过compfoo中定义的字段名查询元素。
我在Postgres中本身没有得到错误,但我的函数的结果是空的。
我做错了什么?

brgchamk

brgchamk1#

RAISE NOTICE应该是你最好的朋友。你可以在代码的某些地方打印一些变量的结果。基本的问题是没有很好地初始化值。arr变量是由NULL值初始化的,任何对NULL的操作都是NULL
另一个问题是select footemp.f1 into result where footemp.f1 = 1;语句。Postgres中的SELECT INTO在结果为空时用NULL值覆盖目标变量。在第二次迭代中,该查询的结果为空集,并且result变量设置在NULL上。
你的例子中最大的问题是编程风格。你使用 *ISAM风格 *,你的代码可能会非常慢。

  • 循环中不要使用array_append,当查询中可以使用array_agg函数,并且不需要循环时,
  • 当不从表中读取数据时不要使用SELECT INTO
  • 不要尝试重复Oracle的模式 BULK COLLECTFOREACH 读取集合。PostgreSQL不是Oracle,使用非常不同的体系结构,这种模式不会提高性能(像Oracle),但可能会损失一些性能。

您的固定代码可能如下所示:

CREATE OR REPLACE FUNCTION public.foo_query()
 RETURNS text
 LANGUAGE plpgsql
AS $function$
declare
  r compfoo;
  arr compfoo [] default '{}'; --<<<
  footemp compfoo;
  result text;
begin
  for r in
     select * from foo where fooid = 1 or fooid = 2
  loop
    arr := array_append(arr, r);
  end loop;

  foreach footemp in array arr
  loop
    if footemp.f1 = 1 then --<<<
      result := footemp.f1;
    end if;
  end loop;

  return result;
end;
$function$
postgres-# ;

它返回了预期的结果。但它是一个完美的例子,说明了如何不写存储过程。不要试图替换存储过程中的SQL。这个过程的所有代码都可以用一个查询来替换。最后,这个代码在处理较大的数据时会非常慢。

相关问题