PostgreSQL中hstore单键关联数组值的插入及替代类型咨询
PostgreSQL存储复杂参数的问题解答
我来帮你拆解这个问题,直接给你实用的解决方案:
1. hstore能否实现单键关联数组元素?
答案是不行。hstore的核心设计是存储字符串类型的键值对,它不支持直接存储数组、嵌套对象这类复杂数据结构。你之前尝试的term => [“lamp”, “blue”]或者ARRAY写法都会报错,本质原因就是hstore无法解析非字符串格式的值。
如果实在要勉强用hstore,只能用变通方案:把数组转换成字符串(比如用逗号分隔)存入,读取时再转成数组。比如插入时写成:
'term => "lamp,blue"'
查询还原数组时用:
SELECT string_to_array(params -> 'term', ',') FROM events_logs;
但这种方式既麻烦又丢失了数组的类型安全性,非常不推荐。
2. 是否有比hstore更适配该需求的数据类型?
必须有!jsonb(或者基础的json类型,优先推荐jsonb)是完美适配的选择。它原生支持JSON的所有结构,包括数组、嵌套对象,而且是二进制存储,查询效率高还支持索引,完全能满足你存储数组参数的需求。
修改后的完整脚本示例
首先调整表结构,把PARAMS的类型改成jsonb:
CREATE TABLE events_logs( EVENT_DATE timestamp without time zone NOT NULL, USER_ID VARCHAR(25) NOT NULL, EVENT_ID integer NOT NULL, EVENT_VALUE NUMERIC, PARAMS jsonb, -- 替换hstore为jsonb PRIMARY KEY (EVENT_DATE,USER_ID,EVENT_ID), CONSTRAINT events_logs_event_id_fkey FOREIGN KEY (EVENT_ID) REFERENCES events (EVENT_ID) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION );
然后插入语句使用标准JSON格式,数组直接用JSON数组语法:
INSERT INTO events_logs (EVENT_DATE,USER_ID,EVENT_ID,EVENT_VALUE,PARAMS) VALUES ('2017-09-13 12:01:00','aed-355-dg25',3,NULL,'{}'), -- 空JSON对象代替空字符串 ('2017-09-13 12:05:00','aed-355-dg25',2,NULL,'{"term": ["lamp", "blue"]}'), -- 原生支持数组 ('2017-09-13 12:06:00','ryf-734-em0',3,NULL,'{}'), ('2017-09-13 12:08:00','ryf-734-em0',2,NULL,'{"term": "rug"}');
jsonb的额外优势
用jsonb后,你还能直接对数组进行查询操作,比如检查term数组是否包含某个元素:
SELECT * FROM events_logs WHERE PARAMS -> 'term' ? 'lamp';
或者展开数组进行分析:
SELECT el.*, unnest_term FROM events_logs el, jsonb_array_elements(el.PARAMS -> 'term') unnest_term;
这些操作都是hstore很难实现的。
内容的提问来源于stack exchange,提问作者godson KALIPE




