当我在JSONB中存储了一个数组时,我正在努力学习连接的语法。我已经搜索了一些例子,我无法找到使其在PostgreSQL 9.6中运行的神奇酱油
我在名为disruption_history
的表中的JSONB列中存储了以下结构。该元素称为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
我得到了
错误:运算符不存在:text = integer
即使我尝试将数字转换为整数,我也得到WHERE
的参数不能返回一个集合。
有人可以帮忙吗?
答案 0 :(得分:1)
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
答案 1 :(得分:0)
您可以使用以下查询:
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)
) ;
请注意,我使用了显式连接(避免使用隐式连接!)。
这里的技巧是将 preRecordedMessageCodes 转换为一组文本,使用jsonb_array_elements_text
function进一步CAST
到整数,然后与ml.component_code
进行比较(使用IN
条件):
您可以在 dbfiddle here
中查看整个设置另请注意,此结构会生成糟糕的执行计划,需要对两个表进行完整的顺序扫描。我无法找到任何有助于查询的索引。
请注意,如果您的数组中包含NULL
s,这将无法运行,我认为这些数组没有意义。
保持秩序:
如果要按顺序保留数组的元素,则需要使用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 here
上观看<强>替代强>:
如果您的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 here
一起检查所有内容 JSON(B)
允许您不进行规范化,也不必考虑您的表格结构,但是您在性能和可维护性方面付出了沉重的代价。