cra*_*ton 1 postgresql stored-procedures insert plpgsql postgresql-9.1
我想在PostgreSQL中做这样的事情.
我试过这个:
CREATE or replace FUNCTION create_patient(_name text, _email text, _phone text
, _password text
, _field1 text, _field2 text, _field3 timestamp, _field4 text
, OUT _pid integer, OUT _id integer
) RETURNS record AS
$$
DECLARE
_id integer;
_type text;
_pid integer;
BEGIN
_type := 'patient';
INSERT into patients (name, email, phone, field1, field2, field3)
VALUES (_name, _email, _phone, _field1, _field2, _field3)
RETURNING id into _pid;
INSERT into users (username, password, type, pid, phone, language)
VALUES (_email, _password, _type, _pid, _phone, _field4)
RETURNING id into _id;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
但是有很多实例我不希望指定一些field1 / field2 / field3 / field4并希望未指定的字段使用表中的默认值.目前这是不可能的,因为要调用此函数我需要指定所有字段.
有没有一种简单的方法可以INSERT在PL/pgSQL中创建包装器过程,我可以在其中指定要插入的字段?
CREATE OR REPLACE FUNCTION create_patient(
_name text = NULL -- always updated, NULL if not provided
,_email text = NULL
,_phone text = NULL
,_password text = NULL
,_field1 text = NULL -- variable parameters
,_field2 text = NULL
,_field3 timestamp = NULL
,_language text = NULL
,_cols text[] = '{field1,field2,field3,language}'
,OUT _pid text
,OUT _id int)
RETURNS record AS
$func$
BEGIN
EXECUTE format(
'INSERT INTO patients (field1, field2, field3, name, email, phone)
VALUES (%s, %s, %s, $4, $5, $6 )
RETURNING id'
,CASE WHEN 'field1' = ANY(_cols) THEN '$1' ELSE 'DEFAULT' END
,CASE WHEN 'field2' = ANY(_cols) THEN '$2' ELSE 'DEFAULT' END
,CASE WHEN 'field3' = ANY(_cols) THEN '$3' ELSE 'DEFAULT' END)
INTO _pid -- return value, also used in 2nd insert
USING _field1, _field2, _field3, _name, _email, _phone;
EXECUTE format(
'INSERT INTO users (username, password, type, pid, phone, language)
VALUES ($1, $2, $$patient$$, $3, $4, %s )
RETURNING id'
,CASE WHEN 'language' = ANY(_cols) THEN '$4' ELSE 'DEFAULT' END)
INTO _id -- return value
USING _email, _password, _pid, _phone, _language;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
SELECT * FROM create_patient('myname','myemail','myphone','mypassword'
,'myfield1','myfield2',NULL,'English','{field2,language,field1}'::text[]);
Run Code Online (Sandbox Code Playgroud)
由于该函数使用命名参数并且每个参数都有一个默认值,您甚至可以像这样调用它:
SELECT * FROM create_patient(_name := 'myname');
Run Code Online (Sandbox Code Playgroud)
如果需要某些非空值,则可能不适用于您的表,但是为了证明您提供命名参数后可以省略任何带有默认值的参数.省略的参数采用声明的默认值(不要与列默认值混淆).更多相关答案:
具有可变数量输入参数的函数
使用命令的DEFAULT关键字INSERT.它使系统插入表的默认列.
替代方案是仅列出INSERT行中获取行中相应项的VALUES列.
您必须使用动态SQL并EXECUTE操纵语句本身,而不仅仅是值.
"摇摆柱"都是field1以field3和language,剩下的就是硬是根据定义.根据需要变化.
我的函数适用于所有情况,您甚至可以提供NULL值而不是列默认值.这需要一个参数来_cols提供要插入列的信息.
如果声明了所有涉及的列NOT NULL- 尚未阐明 - 您可以简化:传递NULL任何应该获取列默认值的列并调整CASE语句.
如果省略_cols,将插入所有字段.作为_cols最后一个IN参数并且具有默认值,您始终可以省略它.
我使用该USING子句EXECUTE将参数作为值传递,并使用动态构建的查询字符串防止SQL注入.
我format()用来简化语句汇编并避免多个赋值.PL/pgSQL更便宜.
不要DECLARE _id和_pid在函数体中,因为它们是由OUT标题中的参数声明并自动返回.
您可以直接type在INSERT语句中插入常量值.这样您就不需要任何变量并保存其他分配.
使用PostgreSQL 9.1进行测试,但应该适用于8.4以来的所有版本 - 除了format()9.1引入的版本.