因为 PostgreSQL 不支持动态计算的表列,所以克服此限制的一种可能方法是使用在this问题的答案中指出的视图。我尝试以下列方式实现此类视图:
CREATE VIEW user_info_view AS
SELECT *,
calculate_bonus_points_for_period(user_info.id) AS bonus_points_period,
calculate_user_level(user_info.id) AS level
FROM user_info;
user_info
表如下:
CREATE TABLE user_info
(
id serial PRIMARY KEY,
card_id text NOT NULL UNIQUE,
name text NOT NULL,
address text NOT NULL,
phone text NOT NULL,
bank_credit bigint NOT NULL,
deposit bigint NOT NULL,
bonus_points bigint NOT NULL
);
用于计算视图列的2个函数如下:
CREATE TYPE user_level AS ENUM ('bronze', 'gold', 'platinum');
----------------------------------------------------------------------
CREATE FUNCTION calculate_bonus_points_for_period(user_id integer)
RETURNS bigint AS
$BODY$
DECLARE
bonus_period smallint;
result bigint;
BEGIN
SELECT settings.bonus_period INTO bonus_period FROM settings;
SELECT sum(bonus_points_earned) INTO result FROM game_pledges
WHERE game_pledges.user_id = calculate_bonus_points_for_period.user_id AND
ts > current_date - interval '1 day' * bonus_period;
RETURN COALESCE(result, 0);
END;
$BODY$
LANGUAGE plpgsql;
----------------------------------------------------------------------
CREATE FUNCTION calculate_user_level(user_id integer)
RETURNS user_level AS
$BODY$
DECLARE
bonus_points_period bigint;
bronze_gold_boundery bigint;
gold_platinum_boundery bigint;
BEGIN
SELECT user_info_view.bonus_points_period
INTO bonus_points_period
FROM user_info_view
WHERE user_id = id;
SELECT settings.bronze_gold_boundery INTO bronze_gold_boundery FROM settings;
SELECT settings.gold_platinum_boundery INTO gold_platinum_boundery FROM settings;
IF bonus_points_period >= gold_platinum_boundery THEN
RETURN 'platinum';
ELSIF bonus_points_period >= bronze_gold_boundery THEN
RETURN 'gold';
ELSE
RETURN 'bronze';
END IF;
END;
$BODY$
LANGUAGE plpgsql;
我在user_info
表中有数据,但是当我用pgAdmin
打开它时,视图为空。一开始,我在game_pledges
表格中有否数据,我希望sum
为0
。有人可以解释为什么视图是空的吗?我期望与user_info
表中的行数相同。
后记:
当我执行SELECT count(*) FROM user_info_view;
时,我发现我的功能有些含糊不清。我纠正了上面的代码并解决了歧义问题,但现在又出现了另一个错误:
ERROR: stack depth limit exceeded
HINT: Increase the configuration parameter "max_stack_depth" (currently 2048kB), after ensuring the platform's stack depth limit is adequate.
CONTEXT: SQL statement "SELECT sum(bonus_points_earned) FROM game_pledges
WHERE game_pledges.user_id = calculate_bonus_points_for_period.user_id AND
ts > current_date - interval '1 day' * bonus_period"