I want to do something like this in PostgreSQL.
I tried this:
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;
But there are a lot of instances where I would not want to specify some of field1 / field2 / field3 / field4 and want the unspecified fields to use the default value in the table. Currently that is not possible, because to call this function I need to specify all fields.
Is there a simple way to create a wrapper procedure for INSERT in PL/pgSQL where I can specify which fields I want to insert?
Use default values for function parameters and dynamic SQL …
Demo function
Call
As the function uses named parameters and each has a default value, you can even call it like this:
May not work for your tables if some non-null values are required, but goes to demonstrate that you can omit any parameters with defaults on them once you provide named parameters. Omitted parameters take the default value as declared (not to be confused with column defaults). More in this related answer:
Functions with variable number of input parameters
Major points
Make use of the
DEFAULTkeyword of theINSERTcommand. It makes the system insert the column default of the table.Alternative would be to only list columns in the
INSERTline that get a corresponding item in theVALUESline.You have to use dynamic SQL and
EXECUTEto manipulate the statement itself, not just the values.“Swing columns” are
field1tofield3andlanguage, the rest is hardwired as per definition. Vary as needed.My function works for all cases, you can even provide a
NULLvalue instead of the column default. That requires a parameter_colsproviding the information which columns are to be be inserted.If all involved columns were declared
NOT NULL– which has not been clarified – you can simplify: passNULLfor any column that should get the column default and adapt theCASEstatements.If you omit
_cols, all fields will be inserted. As_colsis the lastINparameter and has a default value, you can always omit it.I employ the
USINGclause forEXECUTEto pass parameters as values and prevent SQL injection with dynamically built query strings.I employ
format()to simplify statement assembly and avoid multiple assignments. Cheaper in PL/pgSQL.Don’t
DECLARE_idand_pidin the function body, since they are declared byOUTparameters in the header and returned automatically.You can insert a constant value for
typein theINSERTstatement directly. This way you don’t need any variables and save additional assignments.Tested with PostgreSQL 9.1, but should work with all versions since 8.4 – except for
format()which was introduced with 9.1.