在根据另一个视图列计算数据库视图列的值时避免无限递归

时间:2016-11-14 12:46:27

标签: database postgresql recursion sql-view dynamic-columns

我有以下使用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 不同的观点。

是否可以仅使用一个视图解决问题?

1 个答案:

答案 0 :(得分:1)

为什么不呢?

nope

我是否遗漏了OP的内容?

您可以在步骤

中执行此操作
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;