循环遍历数组参数WITHOUT foreach

时间:2012-10-02 04:07:52

标签: postgresql foreach postgresql-9.1 plpgsql postgresql-8.4

CREATE OR REPLACE FUNCTION fnMyFunction(recipients recipient[]) ...

    FOREACH v_recipient IN ARRAY recipients
       LOOP
          v_total := v_total + v_recipient.amount;
          INSERT INTO tmp_recipients(id, amount)
          VALUES(v_recipient.id, v_recipient.amount::numeric(10,2));
    END LOOP;

...

这在开发环境中工作得很好,但刚刚发现发布环境是8.4,它似乎不支持FOREACH构造。我希望有人可以通过数组参数集对循环的替代实现有所了解,并以类似的方式使用数组中的值来避免完整的重构。

我收到的错误消息是:

  

错误:“FOREACH”SQL状态或附近的语法错误:42601上下文:SQL   PL / PgSQL函数中的语句“fnMyFunction”在##

附近

db环境位于共享主机上,因此我没有平台升级选项 我标记了postgres 9.1和8.4,因为该函数在9.x中正常工作但在8.4上失败。

2 个答案:

答案 0 :(得分:2)

使用unnest;我认为这是在8.4。未经测试但我认为是对的:

FOR v_recipient IN SELECT vr FROM unnest(recipients) x(vr)
LOOP
....
END LOOP;

如果你不能这样做,你将不得不使用索引到数组中循环array_length

答案 1 :(得分:1)

您拥有它的方式,一次执行一个INSERT。对于关系数据库,基于集合的操作定期很多比一次迭代一个记录更快。

这应该更简单,更快,并与PostgreSQL 8.4或更高版本一起使用:

INSERT INTO tmp_recipients(id, amount)
SELECT (r.col).*
FROM   (SELECT unnest(recipients) AS col) r

这假定数组的复合基本类型由(id, amount)组成 - 按此顺序 - amount的类型可以强制为numeric(10,2)。否则,或者只是确定,更明确:

INSERT INTO tmp_recipients(id, amount)
SELECT (r.col).id, (r.col).amount::numeric(10,2)
FROM   (SELECT unnest(recipients) AS col) r

(r.col)周围的括号不是可选的。他们需要消除复合类型的语法歧义。