如何拆分列包括键和值到postgres中的单独列中
Posted
技术标签:
【中文标题】如何拆分列包括键和值到postgres中的单独列中【英文标题】:How to break apart a column includes keys and values into separate columns in postgres 【发布时间】:2020-03-29 13:38:10 【问题描述】:我是 postgres 的新手,基本上没有经验。我有一个包含键和值的列的表。我需要编写一个查询,它返回一个表,其中包含表的所有列和附加列作为键作为列名和它下面的值。
我的输入是这样的:
id | name|message
12478| A |img_type:=png,key_id:=f235, client_status:=active, request_status:=open
12598| B |img_type:=none,address_id:=c156, client_status:=active, request_status:=closed
输出将是:
id |name| Img_type|Key_id|address_id|Client_status|Request_status
12478| A | png |f235 |NULL |active | open
12598| B | none |NULL |c156 |active | closed
任何帮助将不胜感激。
【问题讨论】:
你能改变message
内容的格式吗?如果这是一个常规的 JSON 结构,那就容易多了
我已经提供了这些数据来阅读它并在其他程序中使用。我没有尝试更改格式。所以你的意思是在SELECT中基本上将消息列格式更改为json?
不,存储数据为有效的 JSON(即更改您的应用程序以更改格式)
【参考方案1】:
我唯一能想到的就是提取键/值对的正则表达式。
select id, name,
(regexp_match(message, '(img_type:=)([^,]+),0,1'))[2] as img_type,
(regexp_match(message, '(key_id:=)([^,]+),0,1'))[2] as key_id,
(regexp_match(message, '(client_status:=)([^,]+),0,1'))[2] as client_status,
(regexp_match(message, '(request_status:=)([^,]+),0,1'))[2] as request_status
from the_table;
regexp_match
返回一个匹配数组。由于正则表达式包含两组(一组用于“键”,一组用于“值”),[2]
采用数组的第二个元素。
这非常昂贵且容易出错(例如,如果任何值包含 ,
并且您需要处理引用的值)。如果您有机会更改存储值的应用程序,您应该认真考虑更改代码以存储正确的 JSON 值,例如
"img_type": "png", "key_id": "f235", "client_status": "active", "request_status": "open"'
然后你可以使用例如message ->> 'img_type'
检索键 img_type
的值
您可能还需要考虑一个正确规范化的表,其中每个键都是一个真实的列。
【讨论】:
【参考方案2】:我可以用函数来做到这一点。 我对性能很肯定,但这是我的建议:
CREATE TYPE log_type AS (img_type TEXT, key_id TEXT, address_id TEXT, client_status TEXT, request_status TEXT);
CREATE OR REPLACE FUNCTION populate_log(data TEXT)
RETURNS log_type AS
$func$
DECLARE
r log_type;
BEGIN
select x.* into r
from
(
select
json_object(array_agg(array_data)) as json_data
from (
select unnest(string_to_array(trim(unnest(string_to_array(substring(populate_log.data, '[^]+'), ','))), ':=')) as array_data
) d
) d2,
lateral json_to_record(json_data) as x(img_type text, key_id text, address_id text, client_status text, request_status text);
RETURN r;
END
$func$ LANGUAGE plpgsql;
with log_data (id, name, message) as (
values
(12478, 'A', 'img_type:=png,key_id:=f235, client_status:=active, request_status:=open'),
(12598, 'B', 'img_type:=none,address_id:=c156, client_status:=active, request_status:=closed')
)
select id, name, l.*
from log_data, lateral populate_log(message) as l;
你最终在查询中写的内容是这样的,假设数据在一个名为log_data
的表中:
select id, name, l.*
from log_data, lateral populate_log(message) as l;
我认为message
列是一个文本,在 Postgres 中它可能是一个数组,在这种情况下你必须删除一些转换,string_to_array(substring(populate_log.data))
-> populate_log.data
【讨论】:
以上是关于如何拆分列包括键和值到postgres中的单独列中的主要内容,如果未能解决你的问题,请参考以下文章
如何根据 pandas-python 中带有空格的图像拆分列中的值
如何将所有键和值从 Swift 中的 NSDictionary 获取到单独的字符串数组中?