-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);
 私 | バツ
---+---
 1 | 1
 2 | 1
 2 | 2
 3 | 1
 3 | 2
 3 | 3
(6行)
于 2013-02-04T08:16:20.480 に答える