How to use postgresql any with jsonb data

有些话、适合烂在心里 提交于 2019-12-11 01:00:31

问题


Related

see this question

Question

I have a postgresql table that has a column of type jsonb. the json data looks like this

{
   "personal":{
      "gender":"male",
      "contact":{
         "home":{
            "email":"ceo@home.me",
            "phone_number":"5551234"
         },
         "work":{
            "email":"ceo@work.id",
            "phone_number":"5551111"
         }
      },
      ..
      "nationality":"Martian",
      ..
   },
   "employment":{
      "title":"Chief Executive Officer",
      "benefits":[
         "Insurance A",
         "Company Car"
      ],
      ..
   }
}

This query works perfectly well

select employees->'personal'->'contact'->'work'->>'email' 
from employees 
where employees->'personal'->>'nationality' in ('Martian','Terran')

I would like to fetch all employees who have benefits of type Insurance A OR Insurance B, this ugly query works:

 select employees->'personal'->'contact'->'work'->>'email' 
   from employees 
   where employees->'employment'->'benefits' ? 'Insurance A' 
   OR employees->'employment'->'benefits' ? 'Insurance B';

I would like to use any instead like so:

select * from employees 
where employees->'employment'->>'benefits' = 
any('{Insurance A, Insurance B}'::text[]);

but this returns 0 results.. ideas?

What i've also tried

I tried the following syntaxes (all failed):

.. = any({'Insurance A','Insurance B'}::text[]);
.. = any('Insurance A'::text,'Insurance B'::text}::array);
.. = any({'Insurance A'::text,'Insurance B'::text}::array);
.. = any(['Insurance A'::text,'Insurance B'::text]::array);

回答1:


employees->'employment'->'benefits' is a json array, so you should unnest it to use its elements in any comparison. Use the function jsonb_array_elements_text() in lateral join:

select *
from 
    employees, 
    jsonb_array_elements_text(employees->'employment'->'benefits') benefits(benefit)
where
    benefit = any('{Insurance A, Insurance B}'::text[]);

The syntax

from 
    employees, 
    jsonb_array_elements_text(employees->'employment'->'benefits')

is equivalent to

from 
    employees, 
    lateral jsonb_array_elements_text(employees->'employment'->'benefits')

The word lateral may be omitted. For the documentation:

LATERAL can also precede a function-call FROM item, but in this case it is a noise word, because the function expression can refer to earlier FROM items in any case.

See also: What is the difference between LATERAL and a subquery in PostgreSQL?

The syntax

from jsonb_array_elements_text(employees->'employment'->'benefits') benefits(benefit)

is a form of aliasing, per the documentation

Another form of table aliasing gives temporary names to the columns of the table, as well as the table itself:

FROM table_reference [AS] alias ( column1 [, column2 [, ...]] )




回答2:


You can use the containment operator ?| to check if the array contains any of the values you want.

select * from employees 
where employees->'employment'->'benefits' ?| array['Insurance A', 'Insurance B']

If you happen to a case where you want all of the values to be in the array, then there's the ?& operator to check for that.



来源:https://stackoverflow.com/questions/38324360/how-to-use-postgresql-any-with-jsonb-data

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!