PLpgSQL 函数结果上的 FOR 循环

FOR loop on PLpgSQL function result

我写了一个 PLpgSQL 函数应该 return SETOF products table:

CREATE OR REPLACE FUNCTION get_products_by_category
(selected_category_id smallint DEFAULT 1) RETURNS SETOF products AS
$BODY

$BEGIN
RETURN QUERY  (SELECT * FROM products WHERE CategoryID = selected_category_id);
END;

$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF
COST 100
ROWS 1000;

接下来我想在另一个函数中迭代结果(未完成视图,因为我尝试在 PgAdmin III 中添加但出现错误):

DECLARE
    R RECORD;
BEGIN
IF TG_TABLE_NAME != 'Categories' THEN
    RAISE 'This trigger function is for Categories, but was called for %', TG_TABLE_NAME;
FOR R IN get_products_by_category(1) LOOP
    UPDATE products SET CategoryID = NEW.id WHERE id = R.id;
RETURN NEW;

我的想法是我在数据库中有一些产品,它们的默认类别 ID 为 1。然后,当添加新类别时,触发触发器更新 CategoryID(来自新添加的对象)默认产品 CategoryID - 也许这听起来很愚蠢,但我正在学习 Northwind 数据库的触发器,我不得不为自己创建任务。 :)

但是我无法保存它,因为错误 near get_products_by_category(1)。 在 PLpgSQL 中(我使用的是 9.3 版本)是否有可能在 Java:

中编写类似的内容
for (Product product: dao.getProductsByCategory(categoryId))

更新代码:

DECLARE
    selected_products products[];
    product products;
BEGIN
IF TG_TABLE_NAME != 'categories' THEN
    RAISE 'This trigger function is for Categories, but was called for %', TG_TABLE_NAME;
END IF;
selected_products := get_products_by_category(1);
FOR product IN selected_products LOOP
    UPDATE products SET CategoryID = NEW.id
        WHERE id = R.id;
END LOOP;
RETURN NEW;
END;

基本上,你需要阅读手册中的这一章:Looping Through Query Results
关于 plpgsql trigger functions.

CREATE OR REPLACE FUNCTION my_trigger_func()
   RETURNS trigger AS
$func$
DECLARE
    _prod products;
BEGIN
   IF TG_TABLE_NAME <> 'categories' THEN
      RAISE EXCEPTION 'Trigger func for "categories", not for %', TG_TABLE_NAME;
   END IF;

   FOR _prod IN 
      SELECT * FROM get_products_by_category(1)
   LOOP
      UPDATE products p
      SET    categoryid = NEW.id
      WHERE  p.id = _prod.id;
   END LOOP;
   RETURN NEW;
END
$func$  LANGUAGE plpgsql

或者:

...
DECLARE
    _id int;
BEGIN
   ...
   FOR _id IN 
      SELECT id FROM get_products_by_category(1)
   LOOP
      ...
      WHERE  p.id = _id;
...

两者都只是作为概念证明。大多数时候,一个优秀的基于集合的解决方案指日可待。喜欢这里:

UPDATE products p
SET    categoryid = NEW.id
FROM   get_products_by_category(1) x
WHERE  p.id = x.id;

您可以使用像 get_products_by_category(1) 这样的集合返回函数,就像在大多数情况下使用 table 一样。

备注

  • 你必须了解美元报价:

    • Insert text with single quotes in PostgreSQL
  • != 也是有效的,而是使用 SQL 标准运算符 <>.

  • Table 名称不是唯一的。为确保您必须检查 TG_TABLE_NAMETG_TABLE_SCHEMA.

    • How to check if a table exists in a given schema