[英]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.