从技术上讲,这应该“触发”并在将内容添加到详细表中时不断更新汇总表。我想我在代码中遗漏了一些东西?
这应该是一个存储过程。我只需要将其从
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();
术语“存储过程”只是一种误导。就 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