Postgresql
“錯誤:沒有參數 $1”在“EXECUTE .. USING ..;”中plpgsql 中的語句
我有一個 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;
當我呼叫它時,它是成功的:
# 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 文件明確表示這種格式有效且效率更高。
那麼為什麼它沒有按預期工作呢?
您只能將值傳遞給 DML 語句。手冊:
參數符號的另一個限制是它們僅適用於
SELECT
、INSERT
、UPDATE
和DELETE
命令。在其他語句類型(通常稱為實用程序語句)中,您必須以文本方式插入值,即使它們只是數據值。所以
CREATE TABLE
語句不通過USING
子句接受參數,即使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 或更高版本中新的聲明性表分區。帶有範常式式碼和連結的相關答案: