[英]How do I perform a join with a JSONB array structure in PostgreSQL
当我将数组存储在JSONB中时,我正在为联接的语法苦苦挣扎。 我搜索了示例,但找不到使它在PostgreSQL 9.6中起作用的神奇调味料
我有存储在一个表称为JSONB列如下结构disruption_history
。 该元素称为data
:
"message": {
"id": 352,
"preRecordedMessageList": {
"preRecordedMessageCodes": [804, 2110, 1864, 1599]
}
}
然后,我有另一个称为message_library
标准表
component_code | integer | not null
message_text | character varying(255) | not null
我正在尝试为每组消息代码生成文本。 所以像
SELECT
ml.message_text
FROM
message_library ml, disruption_history dh
WHERE
jsonb_array_elements_text(dh.data->'message'->'preRecordedMessageList'
->'preRecordedMessageCodes')) = ml.component_code
我懂了
错误:运算符不存在:文本=整数
即使我尝试将数字转换为整数,我得到的WHERE
参数也不能返回集合。
有人可以帮忙吗?
select message_library.message_text
from disruption_history
join lateral jsonb_array_elements_text(data->'message'->'preRecordedMessageList'->'preRecordedMessageCodes') v
on true
join message_library
on v.value::int = message_library.component_code
您可以使用以下查询:
SELECT
CAST(dh.data->'message'->>'id' AS INTEGER) AS message_id,
ml.message_text
FROM
disruption_history dh
JOIN message_library ml
ON ml.component_code IN
(SELECT
CAST(jsonb_array_elements_text(
dh.data->'message'->'preRecordedMessageList'->'preRecordedMessageCodes'
)
AS INTEGER)
) ;
请注意,我使用了显式联接 (避免使用隐式联接!)。
这里的技巧是通过使用jsonb_array_elements_text
函数将preRecordedMessageCodes转换为一组文本 ,将其进一步CAST
为整数, 然后与ml.component_code
比较(通过使用IN
条件):
您可以在dbfiddle检查整个安装在这里
还要注意,此结构会产生可怕的执行计划,这需要对两个表进行完整的顺序扫描。 我还找不到能够帮助查询的任何索引。
请注意,如果您的数组中包含NULL
,则此方法将无效,我认为这没有任何意义。
保持秩序 :
如果WITH ORDINALITY
顺序保留数组的元素,则需要使用WITH ORDINALITY
谓词不仅获取数组元素,而且获取其相对位置,并将其用于ORDER BY
-- Keeping order
SELECT
CAST(dh.data->'message'->>'id' AS INTEGER) AS message_id,
ml.message_text
FROM
disruption_history dh
JOIN LATERAL
jsonb_array_elements_text(dh.data->'message'->'preRecordedMessageList'->'preRecordedMessageCodes')
WITH ORDINALITY AS x(mc, ord) /* We will want to use 'ord' to order by */
ON true
JOIN message_library ml ON ml.component_code = cast(mc AS INTEGER)
ORDER BY
message_id, ord ;
在这里在dbfiddle上观看
替代方案 :
如果您的json data
的结构始终相同,我强烈建议您对设计进行规范化 (至少部分规范化 ):
CREATE TABLE disruption_history_no_json
(
disruption_history_id SERIAL PRIMARY KEY,
message_id INTEGER,
pre_recorded_message_codes INTEGER[]
) ;
CREATE INDEX idx_disruption_history_no_json_pre_recorded_message_codes
ON disruption_history_no_json USING GIN (pre_recorded_message_codes) ;
将允许一个更简单,有效和简单的查询:
SELECT
message_id,
ml.message_text
FROM
disruption_history_no_json dh
JOIN message_library ml
ON ml.component_code = ANY(pre_recorded_message_codes) ;
在dbfiddle检查一切一起在这里
JSON(B)
允许您不规范化,也不必考虑表结构,但是您在性能和可维护性方面付出了沉重的代价。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.