问题
Here is my table (simplified, only significant columns):
CREATE TABLE things (
id serial primary key
, name varchar
, blueprint json default '{}'
);
And some sample data:
# select * from things;
id | name | blueprint
----+---------+-----------------------------------------------------------------------------
1 | Thing 1 | {}
2 | Thing 2 | {"1":{"name":"Iskapola","wight":"2"}}
3 | Thing 3 | {"1":{"name":"Azamund","weight":"3"}, "2":{"name":"Iskapola","weight":"1"}}
4 | Thing 4 | {"1":{"name":"Ulamir","weight":"1"}, "2":{"name":"Azamund","weight":"1"}}
I'd like to select rows that have 'Azamund'
anywhere under the name
key.
Something like this:
# select * from things where * ->> 'name' = 'Azamund';
id | blueprint
----+----------------------------------------------------------------------------
7 | {"1":{"name":"Azamund","weight":"3"}, "2":{"name":"Iskapola","weight":"1"}}
8 | {"1":{"name":"Ulamir","weight":"1"}, "2":{"name":"Azamund","weight":"1"}}
Data is nested exactly like in the sample (only one level).
Currently we are using PostgreSQL 9.3.5.
Is it possible in PostgreSQL 9.3? Maybe 9.4?
回答1:
Your query is close. json_each() is the key function. Or jsonb_each()
for jsonb
. A couple of improvements:
SELECT *
FROM things t
WHERE EXISTS (
SELECT FROM json_each(t.blueprint) b
WHERE b.value->>'name' ILIKE 'azamund'
);
Old sqlfiddle
db<>fiddle here
json_each()
already returns the value asjson
data type. No need for an additional cast.Better, yet, use a
LATERAL
reference inEXISTS
. This is much cleaner than unnesting with a set-returning function in theSELECT
list. Related:- Call a set-returning function with an array argument multiple times
Use
ILIKE
(~~*
) for the pattern match. Regular expression matches (~
,~*
) are more powerful, but also more expensive. So use the basicLIKE
/ILKE
where you can. Details:- Pattern matching with LIKE, SIMILAR TO or regular expressions in PostgreSQL
Alternative with JSON array
You have already seen my related answer for JSON arrays:
- How do I query using fields inside the new PostgreSQL JSON datatype?
While the query for nested JSON objects seems just as simple, there is superior index support for the array:
- Index for finding an element in a JSON array
May get simpler / more efficient with SQL/JSON in Postgres 12 ...
回答2:
Closest query I can execute (that returns data I need) is:
select *
from (select id, (json_each(blueprint)).value::json->>'name' as name
from stocks) as t
where t.name ~* 'azamund';
Well... Maybe there is something better?
来源:https://stackoverflow.com/questions/28543311/how-to-filter-rows-on-nested-values-in-a-json-column