Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在PostgreSQL中使用JSONB数组结构执行联接_Sql_Postgresql - Fatal编程技术网

如何在PostgreSQL中使用JSONB数组结构执行联接

如何在PostgreSQL中使用JSONB数组结构执行联接,sql,postgresql,Sql,Postgresql,当我在JSONB中存储了一个数组时,我正在努力学习连接的语法。我已经搜索了一些示例,但在PostgreSQL 9.6中找不到使这一功能发挥作用的神奇酱汁 我将以下结构存储在一个名为disruption\u history的表中的JSONB列中。该元素称为数据: "message": { "id": 352, "preRecordedMessageList": { "preRecordedMessageCodes": [804, 2110,

当我在JSONB中存储了一个数组时,我正在努力学习连接的语法。我已经搜索了一些示例,但在PostgreSQL 9.6中找不到使这一功能发挥作用的神奇酱汁

我将以下结构存储在一个名为
disruption\u history
的表中的JSONB列中。该元素称为
数据

"message": {
        "id": 352,
        "preRecordedMessageList": {
            "preRecordedMessageCodes": [804, 2110, 1864, 1599]
        }
}
然后我有另一个标准表,名为
message\u 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

即使我尝试将数字转换为整数,我也会得到
的参数,其中
不能返回一个集合


有人能帮忙吗?

您可以使用以下查询:

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)
            ) ;
注意,我使用了显式连接(避免隐式连接!)

这里的诀窍是使用,将预先录制的消息代码转换为一组文本,进一步将
CAST
转换为整数,然后与
ml.component\u code
进行比较(在
条件下使用
):

您可以在DBFIDLE上检查整个设置

还要注意,这个结构产生了一个糟糕的执行计划,需要对两个表进行完整的顺序扫描。我还没有找到任何有助于查询的索引

请注意,如果数组中有
NULL
s,这将不起作用,我认为这是没有意义的


维持秩序

如果希望保持数组元素的顺序,则需要使用具有顺序性的
谓词,以不仅获取数组元素,还获取其相对位置,并使用它来
按顺序排序

-- 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
数据的结构始终相同,我强烈建议您规范化设计(至少部分):

将允许更简单、高效和更简单的查询:

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)
允许您不进行规范化,也不必考虑您的表结构,但您在性能和可维护性方面付出了高昂的代价。

不确定这是否重要,但最后一行有一个额外的右括号。嘿@Oto,您认为突出显示您的解决方案工作的原因是否有价值。我相信是的,但总有一个教学时间。谢谢,这也很有效,但与我上面描述的排序问题相同。谢谢你的全面回答。不过,JSON数组中的代码似乎是以随机顺序处理的。我需要将它们按照数组的顺序转换成文本,因为它们形成了一个可读的句子。就我而言,我得到的是“大理石拱门”。车站关门了吗“而不是‘大理石拱门车站关闭了’。@Oto的回答也是如此,同样有效。当然,不确定哪种方法最有效。关系理论没有顺序的概念,因此在SQL中执行的大多数操作也没有顺序,除非明确要求给定顺序。您没有将此指定为要求。决不要在SQL中采用顺序。查看保持订单的更新版本。非常感谢。我理解SQL中缺乏秩序。我只是忘了将它作为一个需求添加:-)正如您所说,规范化会更好,但这是一个复杂的变化结构的一部分,JSONB结构就是用来做这种事情的。
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 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