我需要触发器、函数还是过程吗?

问题描述 投票:0回答:1

从技术上讲,这应该“触发”并在将内容添加到详细表中时不断更新汇总表。我想我在代码中遗漏了一些东西?

这应该是一个存储过程。我只需要将其从

FUNCTION
更改为
PROCEDURE
即可吗?它似乎工作正常,但我想现在我有它作为一个功能?

CREATE OR REPLACE FUNCTION update_restaurant()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO summary_table (titles_of_recipes, total_recipes, location_restaurant)

VALUES (NEW.titles_of_recipes, NEW.total_recipes, NEW.location_restaurant);
RETURN NULL;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER summary_insert_trigger
AFTER UPDATE
ON detailed_table
FOR EACH ROW
EXECUTE FUNCTION update_restaurant();

CREATE OR REPLACE FUNCTION refresh_data()
RETURNS VOID AS $$
BEGIN

DELETE FROM detailed_table;
DELETE FROM summary_table;

INSERT INTO detailed_table (total_recipes, inventory_id, location_restaurant, titles_of_recipes)
SELECT
    COUNT(recipe.recipe_id) AS total_recipes,
    inventory.inventory_id AS inventory_id,
    location_restaurant(restaurant.restaurant_id) AS location_restaurant,
    film.title AS titles_of_recipes
FROM 
   recipes
JOIN 
    inventory ON recipe.recipe_id = inventory.recipe_id
JOIN 
    store ON inventory.store_id = store.store_id
GROUP BY
    inventory.inventory_id, location_restaurant(restaurant.restaurant_id), film.title
ORDER BY
    total_of_recipes DESC;

INSERT INTO summary_table (titles_of_recipes, total_of_recipes, location_restaurant)
SELECT
    titles_of_recipes,
    SUM(total_of_recipes) AS total_of_recipes,
    location_restaurant
FROM detailed_table
GROUP BY
    titles_of_recipes, location_restaurant;

RETURN;
END;
$$ LANGUAGE plpgsql;

SELECT refresh_data();
postgresql function triggers
1个回答
0
投票

术语

术语“存储过程”只是一种误导。就 Postgres 而言,这是一个误称。通常,当提到该术语时,您需要 Postgres 中的一个函数。但这只是模棱两可。参见:

Postgres 中的触发器执行函数

CREATE TRIGGER
的语法仍然允许使用误导性关键字
PROCEDURE
,但从 Postgres 11 开始,应该使用更合适的术语
FUNCTION
(除非您需要与过时的 Postgres 版本保持兼容)。参见:

您的代码

“更新汇总表”的工作在代码中分开。函数

refresh_data()
添加实际摘要,触发器复制各个行。

在语法上看起来不错(大部分),但不必要的复杂和昂贵。放下扳机。一切都在函数中完成。一个大的多行

INSERT
比为每一行触发单行
INSERT
便宜得多。另外,您可以使用 CTE 在单个命令中完成这一切。还更便宜。

而且由于您没有返回任何内容,而且它似乎也没有嵌套在任何地方,所以它实际上可能只是一个

PROCEDURE
。 (但这是可选的。)

CREATE OR REPLACE PROCEDURE refresh_data()
  LANGUAGE plpgsql AS
$func$
BEGIN
   DELETE FROM detailed_table;  -- TRUNCATE? See below!
   DELETE FROM summary_table;

   WITH ins1 AS (
      INSERT INTO detailed_table (inventory_id, location_restaurant, titles_of_recipes, total_recipes)
      SELECT i.inventory_id AS inventory_id
           , location_restaurant(restaurant.restaurant_id) AS location_restaurant  -- see below!
           , film.title AS titles_of_recipes
           , count(*) AS total_recipes
      FROM   recipes   r
      JOIN   inventory i USING (recipe_id)
      JOIN   store     s USING (store_id)
      GROUP  BY 1, 2, 3
      ORDER  BY total_of_recipes DESC
      RETURNING *
      )
   INSERT INTO summary_table
         (  titles_of_recipes,   total_recipes,   location_restaurant)
   SELECT i.titles_of_recipes, i.total_recipes, i.location_restaurant
   FROM   ins1 i
   UNION ALL
   SELECT titles_of_recipes
        , SUM(total_of_recipes) AS total_of_recipes  -- may need a cast! like: SUM(total_of_recipes)::int
        , location_restaurant
   FROM   ins1
   GROUP  BY titles_of_recipes, location_restaurant;
END
$func$;

致电:

CALL refresh_data();

参见:

只有

location_restaurant(restaurant.restaurant_id)
没有意义。查询中没有表
restaurant
。解决这个问题。

如果您的桌子很大,请考虑使用

TRUNCATE
而不是
DELETE
。参见:

SUM(<bigint column>)
返回类型
numeric
。您的代码可能需要显式强制转换。喜欢:

SUM(total_of_recipes)::bigint AS total_of_recipes
© www.soinside.com 2019 - 2024. All rights reserved.