Now I use to manually parse json into insert string like so
insert into Table (field1, field2) values (val1, val2)
but its not comfortable way to insert data from json! I've found function json_populate_record and tried to use it:
create table test (id serial, name varchar(50));
insert into test select * from json_populate_record(NULL::test, '{"name": "John"}');
but it fails with the message: null value in column "id" violates not-null constraint PG knows that id is serial but pretends to be a fool. Same it do for all fieds with defaults.
Is there more elegant vay to insert data from json into a table?
PostgreSQL allows you to work on both JSON and SQL data to implement relational and non-relational queries. This way, PostgreSQL allows you to leverage SQL commands for processing data stored in tables of respective database servers.
PostgreSQL offers two types for storing JSON data: json and jsonb . To implement efficient query mechanisms for these data types, PostgreSQL also provides the jsonpath data type described in Section 8.14. 7. The json and jsonb data types accept almost identical sets of values as input.
2) Querying PostgreSQL JSON Data To query data, you can use a SELECT statement like in any other SQL query. You can use the native PostgreSQL operators to query the data in PostgreSQL. The operator -> returns a JSON object field by key. The operator ->> returns a JSON object field by text.
-- Give me params.name (text) from the events table select params->>'name' from events; -- Find only events with a specific name select * from events where params->>'name' = 'Click Button'; -- Give me the first index of a JSON array select params->ids->0 from events; -- Find users where preferences.
There's no easy way for json_populate_record
to return a marker that means "generate this value".
PostgreSQL does not allow you to insert NULL
to specify that a value should be generated. If you ask for NULL
Pg expects to mean NULL
and doesn't want to second-guess you. Additionally it's perfectly OK to have a generated column that has no NOT NULL
constraint, in which case it's perfectly fine to insert NULL
into it.
If you want to have PostgreSQL use the table default for a value there are two ways to do this:
INSERT
column-list; orDEFAULT
, which is only valid in a VALUES
expressionSince you can't use VALUES(DEFAULT, ...)
here, your only option is to omit the column from the INSERT
column-list:
regress=# create table test (id serial primary key, name varchar(50));
CREATE TABLE
regress=# insert into test(name) select name from json_populate_record(NULL::test, '{"name": "John"}');
INSERT 0 1
Yes, this means you must list the columns. Twice, in fact, once in the SELECT
list and once in the INSERT
column-list.
To avoid the need for that this PostgreSQL would need to have a way of specifying DEFAULT
as a value for a record, so json_populate_record
could return DEFAULT
instead of NULL
for columns that aren't defined. That might not be what you intended for all columns and would lead to the question of how DEFAULT
would be treated when json_populate_record
was not being used in an INSERT
expression.
So I guess json_populate_record
might be less useful than you hoped for rows with generated keys.
Continuing from Craig's answer, you probably need to write some sort of stored procedure to perform the necessary dynamic SQL, like as follows:
CREATE OR REPLACE FUNCTION jsoninsert(relname text, reljson text)
RETURNS record AS
$BODY$DECLARE
ret RECORD;
inputstring text;
BEGIN
SELECT string_agg(quote_ident(key),',') INTO inputstring
FROM json_object_keys(reljson::json) AS X (key);
EXECUTE 'INSERT INTO '|| quote_ident(relname)
|| '(' || inputstring || ') SELECT ' || inputstring
|| ' FROM json_populate_record( NULL::' || quote_ident(relname) || ' , json_in($1)) RETURNING *'
INTO ret USING reljson::cstring;
RETURN ret;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Which you'd then call with
SELECT jsoninsert('test', '{"name": "John"}');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With