don*_*llo 5 postgresql dynamic-sql ddl plpgsql postgresql-9.4
我有一个 plpgsql 函数来使用 PostgreSQL 中的表继承创建子表,如下所示:
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;
Run Code Online (Sandbox Code Playgroud)
当我调用它时,它就成功了:
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;
Run Code Online (Sandbox Code Playgroud)
但是,如果我使用该EXECUTE ... USING ...;表单(在上面的代码片段中注释掉),则会收到错误:
# select mk_child(2015,1);
NOTICE: Creating child table child_y15m01
mk_child
--------------
child_y15m01
(1 row)
Run Code Online (Sandbox Code Playgroud)
PostgreSQL 文档明确指出这种格式有效并且效率更高。
那么为什么它没有按预期工作呢?
您只能将值传递给 DML 语句。手册:
对参数符号的另一个限制是它们只能在
SELECT、INSERT、UPDATE和DELETE命令中使用。在其他语句类型(通常称为实用程序语句)中,您必须以文本方式插入值,即使它们只是数据值。
因此,CREATE TABLE语句不接受 viaUSING子句参数,即使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;
Run Code Online (Sandbox Code Playgroud)
有关的:
如果这是关于表分区,请查看 Postgres 10 或更高版本中新的声明性表分区。带有示例代码和链接的相关答案:
| 归档时间: |
|
| 查看次数: |
10126 次 |
| 最近记录: |