1

SOコミュニティの助けを借りてストアドプロシージャを作成しました。関数を書くために、さまざまな質問の答えをまとめてまとめました。

ただし、db(PostgreSQL 8.4)で関数を作成しようとすると、次のエラーが発生します。

ERROR:  syntax error at or near "$4"
LINE 1: ...ank() OVER (ORDER BY  $1 ,  $2 ) /  $3 )::int as  $4  , $1 ,...
                                                            ^

QUERY:   SELECT ceil(rank() OVER (ORDER BY  $1 ,  $2 ) /  $3 )::int as  $4  , $1 ,  $2 ,  $5 ,  $6 ,  $7 ,  $8 ,  $9 ,  $10  FROM foobar WHERE  $2  BETWEEN  $11  AND  $12  AND  $1  = ANY( $13 ) ORDER BY  $1 ,  $2 ,  $4 
CONTEXT:  SQL statement in PL/PgSQL function "custom_group" near line 9

これは私が作成しようとしている関数のコードです:

CREATE OR REPLACE FUNCTION custom_group(start_date DATE, end_date DATE, grouping_period INTEGER, _ids int[] DEFAULT '{}')
RETURNS TABLE (
grp INTEGER,
id INTEGER, 
entry_date DATE,
pop REAL,
hip REAL,
lop REAL,
pcl REAL,
vop BIGINT,
poi BIGINT) AS
$BODY$
BEGIN

IF _ids <> '{}'::int[] THEN -- excludes empty array and NULL
    RETURN QUERY 
                    SELECT ceil(rank() OVER (ORDER BY id, entry_date) / $3)::int as grp
                          ,id, entry_date, pop, hip, lop, pcl, vop, poi
                    FROM   foobar
                    WHERE  entry_date BETWEEN start_date AND end_date AND id = ANY(_ids)
                    ORDER  BY id, entry_date, grp ;

ELSE
    RETURN QUERY 
                    SELECT ceil(rank() OVER (ORDER BY id, entry_date) / $3)::int as grp
                          ,id, entry_date, pop, hip, lop, pcl, vop, poi
                    FROM   foobar
                    WHERE  entry_date BETWEEN start_date AND end_date
                    ORDER  BY id, entry_date, grp ;

END IF;

END;
$BODY$ LANGUAGE plpgsql;

なぜこれらのエラーが発生するのか、そしてどのように修正すればよいのか、誰かが理解できますか?

4

1 に答える 1

1

このエラーは、名前の競合が原因で発生します。

変数は、句grpによって暗黙的に定義されます。RETURNS TABLE関数本体で、列エイリアスと同じ識別子を使用しようとしましたが、これは競合しています。

に別の名前を使用してgrpください-とにかく、列エイリアスは関数の外部には表示されません。

そして、他の列をテーブル修飾します。

CREATE OR REPLACE FUNCTION custom_group(_start_date DATE
                                       ,_end_date DATE
                                       ,_grouping_period INTEGER, 
                                       ,_ids int[] DEFAULT '{}')
RETURNS TABLE (grp int, id int, entry_date date, pop real, hip real,
               lop real, pcl real, vop bigint, poi bigint) AS
$BODY$
BEGIN

IF _ids <> '{}'::int[] THEN -- excludes empty array and NULL
    RETURN QUERY 
    SELECT ceil(rank() OVER (ORDER BY f.id, f.entry_date) / $3)::int AS _grp
          ,f.id, f.entry_date, f.pop, f.hip, f.lop, f.pcl, f.vop, f.poi
    FROM   foobar f
    WHERE  f.entry_date BETWEEN _start_date AND _end_date AND id = ANY(_ids)
    ORDER  BY f.id, f.entry_date, _grp;

ELSE
    RETURN QUERY 
    SELECT ceil(rank() OVER (ORDER BY f.id, f.entry_date) / $3)::int -- no alias
          ,f.id, f.entry_date, f.pop, f.hip, f.lop, f.pcl, f.vop, f.poi
    FROM   foobar f
    WHERE  f.entry_date BETWEEN _start_date AND _end_date
    ORDER  BY f.id, f.entry_date, 1; -- ordinal pos. instead of col alias
END IF;

END;
$BODY$ LANGUAGE plpgsql;

INパラメータにプレフィックスを付ける理由_は同じです。このような名前の競合を避けてください。

この場合、計算列のエイリアスを使用する必要はまったくありません。ORDER BY2番目のクエリで示すように、序数の位置を使用できます。ここでマニュアルを引用します:

各式は、出力列(SELECTリスト項目)の名前または序数にすることも、入力列の値から形成される任意の式にすることもできます。

于 2012-07-23T17:07:30.413 に答える