-1
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE primes
        ( pos SERIAL NOT NULL PRIMARY KEY
        , val INTEGER NOT NULL
        , CONSTRAINT primes_alt UNIQUE (val)
        );

CREATE FUNCTION is_prime(_val INTEGER)
RETURNS BOOLEAN
AS $func$
DECLARE ret BOOLEAN ;
BEGIN

SELECT False INTO ret
WHERE EXISTS (SELECT *
        FROM primes ex
        WHERE ex.val = $1
        OR ( (ex.val * ex.val) <= $1 AND ($1 % ex.val) = 0 )
        );
RETURN COALESCE(ret, True);
END;
$func$ LANGUAGE plpgsql STABLE;

CREATE VIEW vw_prime_step AS (
        -- Note when the table is empty we return {2,3,1} as a bootstrap
        SELECT
           COALESCE(MAX(val) +2,2) AS start
         , COALESCE((MAX(val) * MAX(val))-1, 3) AS stop
         , COALESCE(min(val), 1) AS step
        FROM primes
        );
SELECT * FROM vw_prime_step;

        -- The same as a function.
        -- Works, but is not usable in a query that alters the primes table.
        -- ; even not with the TEMP TABLE construct
CREATE FUNCTION fnc_prime_step ( OUT start INTEGER, OUT stop INTEGER, OUT step INTEGER)
RETURNS RECORD
AS $func$
BEGIN
/***
CREATE TEMP TABLE tmp_limits
        ON COMMIT DROP
        AS SELECT ps.start,ps.stop,ps.step FROM vw_prime_step ps
        ;
-- RETURN QUERY 
SELECT tl.start,tl.stop,tl.step INTO $1,$2,$3
FROM tmp_limits tl
LIMIT 1
        ; 
***/
SELECT tl.start,tl.stop,tl.step INTO $1,$2,$3
FROM vw_prime_step tl
LIMIT 1;
END;
$func$
-- Try lying ...
-- IMMUTABLE LANGUAGE plpgsql;
-- Try lying ...
Stable LANGUAGE plpgsql;

        -- This works
SELECT * FROM fnc_prime_step();
INSERT INTO primes (val)
SELECT gs FROM fnc_prime_step() sss
 , generate_series( 2, 3, 1 ) gs
WHERE is_prime(gs) = True
        ;
        -- This works
SELECT * FROM fnc_prime_step();
INSERT INTO primes (val)
SELECT gs FROM fnc_prime_step() sss
 , generate_series( 5, 24, 2 ) gs
WHERE is_prime(gs) = True
        ;

        -- This does not work
        -- ERROR:  function expression in FROM cannot refer to other relations of same query level:1
SELECT * FROM fnc_prime_step();
INSERT INTO primes (val)
SELECT gs FROM fnc_prime_step() sss
 , generate_series( sss.start, sss.stop, sss.step ) gs
WHERE is_prime(gs) = True
        ;

SELECT * FROM primes;
SELECT * FROM fnc_prime_step();

当然,这个问题纯粹是假设性的,我还没有愚蠢到试图在 DBMS 中计算素数表。但问题仍然存在:有没有一种干净的方法来解决没有 的问题LATERAL

正如你所看到的,我尝试了一个视图(不起作用),围绕这个视图的函数(也不起作用),这个函数中的一个临时表(njet),并调整了函数的属性。

下一步可能是一些触发黑客(但我真的非常讨厌触发器,主要是因为它们对于 DBMS 模式的严格性是不可见的)

4

1 回答 1

1

您可以在目标列表中使用 SRF 功能,但应该有一些奇怪的极端情况。横向是最好的。

postgres=# select i, generate_series(1,i) X from generate_series(1,3) g(i);
 我 | X
---+---
 1 | 1
 2 | 1
 2 | 2
 3 | 1
 3 | 2
 3 | 3
(6 行)
于 2013-02-04T08:16:20.480 回答