Reputation: 5930
TL;DR; In short, what I need is to somehow cast text
to unknown
from where Postgres will magically cast that to correct type; or some alternative solution to this while keeping in mind things that I want to avoid.
Error in question:
ERROR: column "id" is of type integer but expression is of type text
Say I've got this table:
CREATE TEMP TABLE unknown_test (
id int,
some_timestamp timestamp,
value1 int,
value2 int,
value3 text);
Currently I'm doing DML on that table with queries like that:
INSERT INTO unknown_test (id, some_timestamp, value1, value2, value3)
VALUES ('5', '2018-01-10 14:11:03.763396', '3', '15', 'test2');
So values are unknown
type and Postgres has some kind of built in cast for that (it is not in select * from pg_cast where castsource = 'unknown'::regtype;
). This works, but is somewhat slow.
What I want to do is this (obviously I have actual table, not values()
):
INSERT INTO unknown_test (id, some_timestamp, value1, value2, value3)
SELECT json_data->>'id', json_data->>'some_timestamp', json_data->>'value1', json_data->>'value2', json_data->>'value3'
FROM (VALUES (jsonb_build_object('id', 1, 'some_timestamp', now(), 'value1', 21, 'value2', 5, 'value3', 'test')),
(jsonb_build_object('id', 2, 'some_timestamp', now(), 'value1', 22, 'value2', 15, 'value3', 'test2')),
(jsonb_build_object('id', 3, 'some_timestamp', now(), 'value1', 32, 'value2', 25, 'value3', 'test5')),
(jsonb_build_object('id', 4, 'some_timestamp', now(), 'value1', 42, 'value2', 55, 'value3', 'test7'))
) AS j(json_data);
Sadly, those will give text
type and will complain that I need to explicitly cast it. I can't do that, because I don't know what types those are. I could find out of course by checking pg_catalog
or by storing in json data info about type. Both of those require some additional computation and/or storage and I want to avoid any unnecessary overhead to this (my pg_catalog is really fat).
Second thing I want to avoid is CREATE CAST
for text type, unless someone can assure me it won't break anything.
Doing loop and dynamic SQL to get unknown
type is my current approach and I need something faster, so my idea was not to use loop, but table instead.
Upvotes: 0
Views: 894
Reputation:
You can use jsonb_populate_record
for this:
SELECT (jsonb_populate_record(null::unknown_test, json_data)).*
FROM ...
This will create a record of the same type as the table unknown_test
and then the whole record is expanded into individual columns using the (...).*
syntax.
This requires that the (first level) keys in the JSON document have exactly the same names as the columns in the table.
Upvotes: 2