次のように、PostgreSQLのテーブル継承を使用して子テーブルを作成するplpgsql関数があります。
CREATE TABLE parent_table (
value integer,
end_time timestamp without time zone
);
CREATE OR REPLACE FUNCTION mk_child(_year INTEGER, _month INTEGER)
RETURNS text AS $$
DECLARE
tname varchar;
start_date date;
end_date date;
next_month varchar := (_month + 1)::text;
next_year varchar := (_year + 1)::text;
BEGIN
tname := 'child_y' || substring(_year::text from 3 for 2)
|| 'm' || lpad(_month::text, 2, '0');
start_date := DATE (_year::text || '-' || _month::text || '-01');
IF ( _month = 12 ) THEN
end_date := DATE (next_year || '-01-01');
ELSE
end_date := DATE (_year::text || '-' || next_month || '-01');
END IF;
RAISE NOTICE 'Creating child table %', tname;
EXECUTE format('CREATE TABLE %I ( CHECK ( end_time >= %L AND end_time < %L ) )
INHERITS (parent_table)',
tname, start_date, end_date);
-- EXECUTE format('CREATE TABLE %I ( CHECK ( end_time >= $1 AND end_time < $2 ) )
-- INHERITS (parent_table)',
-- tname)
-- USING start_date, end_date;
RETURN tname;
END
$$ LANGUAGE plpgsql;
私がそれを呼ぶとき、それは成功しています:
# select mk_child(2015,1);
NOTICE: Creating child table child_y15m01
mk_child
--------------
child_y15m01
(1 row)
ただし、EXECUTE ... USING ...;
フォーム(上記のスニペットでコメント化)、エラーが発生します:
# select mk_child(2015,2); NOTICE: Creating child table child_y15m02 ERROR: there is no parameter $1 CONTEXT: SQL statement "CREATE TABLE child_y15m02 ( CHECK ( end_time >= $1 AND end_time < $2 ) ) INHERITS (parent_table)" PL/pgSQL function mk_child(integer,integer) line 21 at EXECUTE statement
PostgreSQL docs この形式が機能し、より効率的であることを明示的に述べます。
では、なぜ期待どおりに機能しないのでしょうか。
値はDMLステートメントにのみ渡すことができます。 マニュアルの説明:
パラメータシンボルのもう1つの制限は、
SELECT
、INSERT
、UPDATE
、およびDELETE
コマンドでのみ機能することです。他のステートメントタイプ(一般的にユーティリティステートメントと呼ばれます)では、値が単なるデータ値であっても、テキストで値を挿入する必要があります。
そう CREATE TABLE
ステートメントは、USING
制約lookのような式がパラメーター化されている可能性のある値であっても、CHECK
句を介したパラメーターを受け入れません。
それはさておき、関数を大幅に簡略化できます。
CREATE OR REPLACE FUNCTION mk_child(_year int, _month int)
RETURNS text AS
$func$
DECLARE
start_date date := to_date(_year::text || _month::text, 'YYYYMM');
tname text := to_char(start_date , '"child_y"YY"m"MM');
BEGIN
RAISE NOTICE 'Creating child table %', tname;
EXECUTE format('
CREATE TABLE %I (CHECK (end_time >= %L AND end_time < %L))
INHERITS (parent_table)'
, tname, start_date, (start_date + interval '1 month')::date);
RETURN tname;
END
$func$ LANGUAGE plpgsql;
関連:
これがテーブルのパーティション分割に関するものである場合は、Postgres 10以降の新しい宣言的なテーブルのパーティション分割を参照してください。サンプルコードとリンクを含む関連する回答: