自动将值类型转换为列类型

时间:2018-01-10 13:33:50

标签: postgresql postgresql-9.6

TL; DR;简而言之,我需要的是以某种方式将text投射到unknown,Postgres会将其神奇地投射到正确的类型;或者一些替代解决方案,同时记住我想避免的事情。

有问题:

ERROR: column "id" is of type integer but expression is of type text

说我有这张桌子:

CREATE TEMP TABLE unknown_test (
  id int,
  some_timestamp timestamp,
  value1 int,
  value2 int,
  value3 text);

目前我正在该桌面上使用类似的查询进行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;中)。这有效,但有点慢。

我想要做的是(显然我有实际的表格,而不是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中存储有关类型的数据信息来找到答案。这两个都需要一些额外的计算和/或存储,我想避免任何不必要的开销(我的pg_catalog真的很胖)。

我要避免的第二件事是文本类型为CREATE CAST,除非有人可以向我保证它不会破坏任何内容。

执行循环和动态SQL获取unknown类型是我当前的方法,我需要更快的东西,所以我的想法不是使用循环,而是使用表。

1 个答案:

答案 0 :(得分:2)

您可以使用jsonb_populate_record

SELECT (jsonb_populate_record(null::unknown_test, json_data)).*
FROM ...

这将创建与表unknown_test相同类型的记录,然后使用(...).*语法将整个记录扩展为单个列。

这要求JSON文档中的(第一级)键与完全的名称与表中的列相同。