根据另一个视图列计算数据库视图列的值时避免无限递归
Avoiding infinite recursion when calculating value of database view column depending on another view column
我有以下使用PostgreSQL视图的案例。我必须根据另一个动态计算的视图列的值动态计算视图列的值。这是代码的简化版本:
BEGIN;
CREATE TABLE test
(
id serial PRIMARY KEY,
value integer NOT NULL
);
INSERT INTO test VALUES
(1, 13),
(2, 42);
CREATE FUNCTION inc(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN value + 1;
END;
$BODY$
LANGUAGE plpgsql;
CREATE FUNCTION double(id integer)
RETURNS integer AS
$BODY$
DECLARE
local_value integer;
BEGIN
SELECT value_1 INTO local_value
FROM test_view WHERE double.id = test_view.id;
RETURN 2 * local_value;
END;
$BODY$
LANGUAGE plpgsql;
CREATE VIEW test_view AS
SELECT *,
inc(test.value) AS value_1,
double(test.id) AS value_2
FROM test;
COMMIT;
但是由于第二个函数中的以下语句,这段代码陷入了无限递归。
SELECT value_1 INTO local_value
FROM test_view WHERE double.id = test_view.id;
准确错误如下:
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: PL/pgSQL function inc(integer) line 3 at RETURN
SQL statement "SELECT value_1 FROM test_view WHERE double.id = test_view.id"
PL/pgSQL function double(integer) line 5 at SQL statement
使用第二个视图可以很容易地解决这个问题。例如:
CREATE FUNCTION double(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN 2 * value;
END;
$BODY$
LANGUAGE plpgsql;
CREATE VIEW test_view_1 AS
SELECT *,
inc(test.value) AS value_1
FROM test;
CREATE VIEW test_view_2 AS
SELECT *,
double(test_view_1.value_1) AS value_2
FROM test_view_1;
但我不喜欢这种方法,因为它需要创建第二个视图。在我有 n 不同值的情况下,它不会缩放,每个值取决于前一个值。那我肯定有n个不同的看法。
是否可以只用一个视图解决问题?
为什么不呢?
CREATE FUNCTION inc(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN value + 1;
END;
$BODY$
LANGUAGE plpgsql;
CREATE FUNCTION double(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN 2 * value;
END;
$BODY$
LANGUAGE plpgsql;
CREATE VIEW test_view AS
SELECT *,double(value_1) AS value_2 FROM
(SELECT *,
inc(test.value) AS value_1
FROM test) x;
select * from test_view;
我是不是漏掉了 OP 里的东西?
您可以在第
步完成
CREATE OR REPLACE FUNCTION incdouble(value integer)
RETURNS RECORD AS
$BODY$
DECLARE
linc integer;
ret RECORD;
BEGIN
linc := value + 1;
SELECT linc,linc*2 INTO ret;
RETURN ret;
END;
$BODY$
LANGUAGE plpgsql ;
select * from test t,incdouble(t.value) as (i integer ,d integer)
我有以下使用PostgreSQL视图的案例。我必须根据另一个动态计算的视图列的值动态计算视图列的值。这是代码的简化版本:
BEGIN;
CREATE TABLE test
(
id serial PRIMARY KEY,
value integer NOT NULL
);
INSERT INTO test VALUES
(1, 13),
(2, 42);
CREATE FUNCTION inc(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN value + 1;
END;
$BODY$
LANGUAGE plpgsql;
CREATE FUNCTION double(id integer)
RETURNS integer AS
$BODY$
DECLARE
local_value integer;
BEGIN
SELECT value_1 INTO local_value
FROM test_view WHERE double.id = test_view.id;
RETURN 2 * local_value;
END;
$BODY$
LANGUAGE plpgsql;
CREATE VIEW test_view AS
SELECT *,
inc(test.value) AS value_1,
double(test.id) AS value_2
FROM test;
COMMIT;
但是由于第二个函数中的以下语句,这段代码陷入了无限递归。
SELECT value_1 INTO local_value
FROM test_view WHERE double.id = test_view.id;
准确错误如下:
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: PL/pgSQL function inc(integer) line 3 at RETURN
SQL statement "SELECT value_1 FROM test_view WHERE double.id = test_view.id"
PL/pgSQL function double(integer) line 5 at SQL statement
使用第二个视图可以很容易地解决这个问题。例如:
CREATE FUNCTION double(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN 2 * value;
END;
$BODY$
LANGUAGE plpgsql;
CREATE VIEW test_view_1 AS
SELECT *,
inc(test.value) AS value_1
FROM test;
CREATE VIEW test_view_2 AS
SELECT *,
double(test_view_1.value_1) AS value_2
FROM test_view_1;
但我不喜欢这种方法,因为它需要创建第二个视图。在我有 n 不同值的情况下,它不会缩放,每个值取决于前一个值。那我肯定有n个不同的看法。
是否可以只用一个视图解决问题?
为什么不呢?
CREATE FUNCTION inc(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN value + 1;
END;
$BODY$
LANGUAGE plpgsql;
CREATE FUNCTION double(value integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN 2 * value;
END;
$BODY$
LANGUAGE plpgsql;
CREATE VIEW test_view AS
SELECT *,double(value_1) AS value_2 FROM
(SELECT *,
inc(test.value) AS value_1
FROM test) x;
select * from test_view;
我是不是漏掉了 OP 里的东西?
您可以在第
步完成CREATE OR REPLACE FUNCTION incdouble(value integer)
RETURNS RECORD AS
$BODY$
DECLARE
linc integer;
ret RECORD;
BEGIN
linc := value + 1;
SELECT linc,linc*2 INTO ret;
RETURN ret;
END;
$BODY$
LANGUAGE plpgsql ;
select * from test t,incdouble(t.value) as (i integer ,d integer)