将列中的键值转换为 hstore 或 jsonb 列的正则表达式?

regex to convert key values in a column to an hstore or jsonb column?

我有一个数据库,其中有一个名为 activity 的 table 和一个名为 detail 的列,该列不幸地表示为 key/value 对:

Key ID=[813],\n
Key Name=[Name of Key],\n
Some Field=[2732],\n
Another Field=[2751],\n
Description=[A text string here],\n
Location=[sometext],\n
Other ID=[2360578],\n

从上面的格式中可能很清楚,这是每行一个值,\n 是一个换行符,所以总是有一个额外的换行符。我试图避免让外部程序处理这些数据,所以我正在研究 postgresql 的正则表达式函数。目标是将其转换为 jsonb 或 hstore 列,我真的不在乎哪个。

table 的架构如下:

CREATE TABLE activity
(
  id integer NOT NULL,
  activity_type integer NOT NULL,
  ts timestamp with time zone,
  detail text NOT NULL,
  details_hstore hstore,
  details_jsonb jsonb,
  CONSTRAINT activity_pkey PRIMARY KEY (id),
);

所以我想 运行 一个 UPDATE,我用来自 detail 的处理数据更新 details_jsonbdetails_hstore

这个:

select regexp_matches(activity.detail, '(.*?)=\[(.*?)\]\,[\r|\n]', 'g') as val from activity

给我这些单独的行(这是来自 pgadmin,我假设这些都是字符串):

{"Key ID",813}
{"Key Name","Name of Key"}
{"Some Field",2732}
{"Another Field",2751}
{Description,"A text string here"}
{Location,sometext}
{"Other ID",2360578}

我不是正则表达式高手,但我认为我需要某种分组。此外,它作为某种文本数组返回,但我真正想要的是 jsonb

{"Key ID": "813", "Key Name": "Name of Key"}

甚至更好,如果它只是一个数字那么

{"Key ID": 813, "Key Name": "Name of Key"}

and/or 相当于 hstore。

我觉得我离这个目标还有很多 regex-in-postgres 概念。

这种正则表达式更新太多以至于无法在更新中工作吗?即 update activity set details_jsonb = [[insane regex here]]? hstore 也是一个选项(虽然我喜欢 jsonb 有类型),所以如果像 hstore(text[]) 这样的 hstore 函数更容易,那也很好。

我是不是疯了,我是否需要只编写一个不在 postgresql 中的外部进程来执行此操作?

我会先将单个值拆分成多行。然后可以将每一行转换为一个数组,从中可以将其聚合到一个 JSON 对象中:

select string_to_array(regexp_replace(t.line, '(^\s+)|(\s+$)', '', 'g'), '=')
from activity a, regexp_split_to_table(a.detail, ',\s*\n') t (line)

这个returns下面的:

element                             
------------------------------------
{KeyID,[813]}                       
{"Key Name","[Name of Key]"}        
{"Some Field",[2732]}               
{"Another Field",[2751]}            
{Description,"[A text string here]"}
{Location,[sometext]}               
{"Other ID",[2360578]}              
{}

detail 值拆分为多行的正则表达式可能需要一些改进。

regexp_replace(t.line, '(^\s+)|(\s+$)', '', 'g') 那里有 trim 值,然后再将它们转换为数组。

现在可以将其聚合为单个 JSON 值,或者每行可以转换为单个 hstore 值(遗憾的是没有 hstore_agg()

with activity (detail) as (
  values (
'Key ID=[813],
Key Name=[Name of Key],
Some Field=[2732],
Another Field=[2751],
Description=[A text string here],
Location=[sometext],
Other ID=[2360578],
')
), elements (element) as ( 
  select string_to_array(regexp_replace(t.line, '\s', ''), '=')
  from activity a, regexp_split_to_table(a.detail, ',') t (line)
) 
select json_agg(jsonb_object(element))
from elements
where cardinality(element) > 1 -- this removes the empty line

上面returns一个JSON对象:

[ { "KeyID" : "[813]" },
  { "Key Name" : "[Name of Key]" },
  { "Some Field" : "[2732]" },
  { "Another Field" : "[2751]" },
  { "Description" : "[A text string here]" },
  { "Location" : "[sometext]" },
  { "Other ID" : "[2360578]" }
]