自动将值类型转换为列类型
Automatically cast value type to column type
TL;DR;简而言之,我需要的是以某种方式将 text
转换为 unknown
,Postgres 会神奇地将其转换为正确的类型;或一些替代解决方案,同时牢记我想避免的事情。
问题错误:
ERROR: column "id" is of type integer but expression is of type text
说我有这个 table:
CREATE TEMP TABLE unknown_test (
id int,
some_timestamp timestamp,
value1 int,
value2 int,
value3 text);
目前我正在 table 上进行 DML,查询如下:
INSERT INTO unknown_test (id, some_timestamp, value1, value2, value3)
VALUES ('5', '2018-01-10 14:11:03.763396', '3', '15', 'test2');
所以值是 unknown
类型并且 Postgres 有某种内置的转换(它不在 select * from pg_cast where castsource = 'unknown'::regtype;
中)。这有效,但有点慢。
我想做的是这个(显然我有实际的table,而不是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);
遗憾的是,那些会给出 text
类型并会抱怨我需要显式转换它。我不能那样做,因为我不知道那些是什么类型。当然,我可以通过检查 pg_catalog
或在 json 中存储有关类型的数据信息来找出答案。这两个都需要一些额外的计算 and/or 存储,我想避免任何不必要的开销(我的 pg_catalog 真的很胖)。
我想避免的第二件事是 CREATE CAST
文本类型,除非有人可以向我保证它不会破坏任何东西。
执行循环和动态 SQL 以获得 unknown
类型是我目前的方法,我需要更快的东西,所以我的想法不是使用循环,而是 table。
您可以为此使用 jsonb_populate_record
:
SELECT (jsonb_populate_record(null::unknown_test, json_data)).*
FROM ...
这将创建与 table unknown_test
相同类型的记录,然后使用 (...).*
语法将整个记录扩展为单独的列。
这要求 JSON 文档中的(第一级)键与 table 中的列具有完全相同的名称。
TL;DR;简而言之,我需要的是以某种方式将 text
转换为 unknown
,Postgres 会神奇地将其转换为正确的类型;或一些替代解决方案,同时牢记我想避免的事情。
问题错误:
ERROR: column "id" is of type integer but expression is of type text
说我有这个 table:
CREATE TEMP TABLE unknown_test (
id int,
some_timestamp timestamp,
value1 int,
value2 int,
value3 text);
目前我正在 table 上进行 DML,查询如下:
INSERT INTO unknown_test (id, some_timestamp, value1, value2, value3)
VALUES ('5', '2018-01-10 14:11:03.763396', '3', '15', 'test2');
所以值是 unknown
类型并且 Postgres 有某种内置的转换(它不在 select * from pg_cast where castsource = 'unknown'::regtype;
中)。这有效,但有点慢。
我想做的是这个(显然我有实际的table,而不是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);
遗憾的是,那些会给出 text
类型并会抱怨我需要显式转换它。我不能那样做,因为我不知道那些是什么类型。当然,我可以通过检查 pg_catalog
或在 json 中存储有关类型的数据信息来找出答案。这两个都需要一些额外的计算 and/or 存储,我想避免任何不必要的开销(我的 pg_catalog 真的很胖)。
我想避免的第二件事是 CREATE CAST
文本类型,除非有人可以向我保证它不会破坏任何东西。
执行循环和动态 SQL 以获得 unknown
类型是我目前的方法,我需要更快的东西,所以我的想法不是使用循环,而是 table。
您可以为此使用 jsonb_populate_record
:
SELECT (jsonb_populate_record(null::unknown_test, json_data)).*
FROM ...
这将创建与 table unknown_test
相同类型的记录,然后使用 (...).*
语法将整个记录扩展为单独的列。
这要求 JSON 文档中的(第一级)键与 table 中的列具有完全相同的名称。