如何在未订购的JSON数组的Postgres中从JSONB获得价值

发布于 2025-02-06 13:55:17 字数 1301 浏览 3 评论 0原文

我在Postgres JSONB字段中使用了这样的数据。每个工人都可以有几个电话号码。工人可以或不工作的电话。工作的电话号码可以是阵列中的第一个或最后一个(未订购)。

INSERT INTO "contacts" ("id", "json") VALUES
(101, ' 
{
    "add-date": "2022-06-04",
    "workers": [
        {
            "name": "Alex",
            "phones": [
                { "type": "HOME", "number": 926117171 },                
                { "type": "WORK", "number": 916100203 },                
                { "type": "CELL", "number": 911463212 }             
            ]
        },
        {
            "name": "Maria",
            "phones": [
                { "type": "HOME", "number": 919351948 },
                { "type": "WORK", "number": 915532355 }
            ]
        }
    ]
}
'),
(102, '
{
    "add-date": "2022-06-05",
    "workers": [
        {
            "name": "Pablo",
            "phones": [
                { "type": "CELL", "number": 913456719 }
            ]
        },
        {
            "name": "Nina",
            "phones": [
                { "type": "WORK", "number": 915532321 },
                { "type": "CELL", "number": 919455354 }
            ]
        }
    ]
}
');

我需要选择和显示具有工作号码的工人表,这样的工人:

Alex   | 916100203
Maria  | 915532355
Nina   | 915532321

我只能使用postresql中的SQL+JSONB查询来做到这一点?

I have in Postgres jsonb field with data like this. Every worker can have several phone numbers. Worker can have or not work's phone. Work's phone number can be first or last in array (not ordered).

INSERT INTO "contacts" ("id", "json") VALUES
(101, ' 
{
    "add-date": "2022-06-04",
    "workers": [
        {
            "name": "Alex",
            "phones": [
                { "type": "HOME", "number": 926117171 },                
                { "type": "WORK", "number": 916100203 },                
                { "type": "CELL", "number": 911463212 }             
            ]
        },
        {
            "name": "Maria",
            "phones": [
                { "type": "HOME", "number": 919351948 },
                { "type": "WORK", "number": 915532355 }
            ]
        }
    ]
}
'),
(102, '
{
    "add-date": "2022-06-05",
    "workers": [
        {
            "name": "Pablo",
            "phones": [
                { "type": "CELL", "number": 913456719 }
            ]
        },
        {
            "name": "Nina",
            "phones": [
                { "type": "WORK", "number": 915532321 },
                { "type": "CELL", "number": 919455354 }
            ]
        }
    ]
}
');

And I need to select and show table of workers who has work's number, like this:

Alex   | 916100203
Maria  | 915532355
Nina   | 915532321

Can I do it only with SQL+jsonb queries in Postresql and how?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦在深巷 2025-02-13 13:55:17

以下执行此操作:

select c.id, w.value ->> 'name' as name,
       jsonb_path_query_first(w.value, '$.phones[*] ? (@.type == "WORK")') ->> 'number' as work_number
from contacts c
  cross join jsonb_array_elements("json" -> 'workers') as w(value)
where w.value @> '{"phones": [{"type": "WORK"}]}'
;

交叉加入JSONB_ARRAY_ELEMENTS(“ JSON” - >'工人')将所有工人从JSON值中提取为行。然后,其中的子句限制了那些实际包含一个工作号的行。

这会产生类似的内容:

id  | value                                                                                                                                            
----+--------------------------------------------------------------------------------------------------------------------------------------------------
101 | {"name": "Alex", "phones": [{"type": "HOME", "number": 926117171}, {"type": "WORK", "number": 916100203}, {"type": "CELL", "number": 911463212}]}
101 | {"name": "Maria", "phones": [{"type": "HOME", "number": 919351948}, {"type": "WORK", "number": 915532355}]}                                      
102 | {"name": "Nina", "phones": [{"type": "WORK", "number": 915532321}, {"type": "CELL", "number": 919455354}]}                                       

现在选择列表然后将工人的名称提取为一列,并使用JSON路径查询来查找手机数组中的第一个工作号。

如果有一个以上的阵列元素和工人的工作电话,这将无法正常工作。

The following does this:

select c.id, w.value ->> 'name' as name,
       jsonb_path_query_first(w.value, '$.phones[*] ? (@.type == "WORK")') ->> 'number' as work_number
from contacts c
  cross join jsonb_array_elements("json" -> 'workers') as w(value)
where w.value @> '{"phones": [{"type": "WORK"}]}'
;

The cross join jsonb_array_elements("json" -> 'workers') extracts all workers as rows from the JSON value. The where clause then limits that those rows that actually contain a work number.

This produces something like this:

id  | value                                                                                                                                            
----+--------------------------------------------------------------------------------------------------------------------------------------------------
101 | {"name": "Alex", "phones": [{"type": "HOME", "number": 926117171}, {"type": "WORK", "number": 916100203}, {"type": "CELL", "number": 911463212}]}
101 | {"name": "Maria", "phones": [{"type": "HOME", "number": 919351948}, {"type": "WORK", "number": 915532355}]}                                      
102 | {"name": "Nina", "phones": [{"type": "WORK", "number": 915532321}, {"type": "CELL", "number": 919455354}]}                                       

Now the SELECT list then extracts the worker's name name as one column and uses a JSON path query to find the first WORK number in the array of phones.

This will not work correctly if there is more than one array elements with a WORK phone for a worker.

Online example

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文