I have a postgreSQL table that contains the following:
select * from ci_grp;
ci | grp
------------+-------------------------------------------------------------------------------------------
Ci1 | [{"Name":"TEAM.Virtu"},{"Name":"TECH.LinuxDevice"}]
Ci2 | [{"Name":"TECH.LinuxDevice"},{"Name":"TEAM.Monitoring"}]
Ci3 | [{"Name":"TEAM.Noc"},{"Name":"TEAM.Virtu"},{"Name":"TECH.DellEsx"},{"Name":"TECH.SNMP"}]
Ci4 | [{"Name":"TEAM.Monitoring"},{"Name":"TECH.Postgresql"}]
Ci5 | [{"Name":"TEAM.Monitoring"},{"Name":"TECH.LinuxDevice"},{"Name":"TECH.ZabbixProxy"}]
I need to get a reply that would only returns the CI names where ‘grp’ is both {"Name":"TECH.LinuxDevice"} and {"Name":"TEAM.Monitoring"} ==> Thus, Ci2 and Ci5. What would be the best SQL query to get this?
I’ve first tried:
WITH
GetGrps AS (SELECT ci, json_array_elements("grp")->>'Name' AS grp from ci_grp)
SELECT GetGrps.ci, GetGrps.grp
FROM GetGrps
WHERE GetGrps.grp LIKE '%TECH.Monitoring%';
The pb with that query is I that I get 1 record per Key/Value pair:
ci | grp
---------------+------------------------
Ci1 | TEAM.Virtu
Ci1 | TECH.LinuxDevice
Ci2 | TECH.LinuxDevice
Ci2 | TEAM.Monitoring
Ci3 | TEAM.Noc
Ci3 | TEAM.Virtu
Ci3 | TECH.DellEsx
Ci3 | TEAM.SNMP
Ci4 | TEAM.Monitoring
Ci4 | TECH.Postgresql
Ci5 | TEAM.Monitoring
Ci5 | TECH.LinuxDevice
Ci5 | TECH.ZabbixProxy
Thus of course, when I try to add
AND GetGrps.grp LIKE '%TECH.LinuxDevice%'
I get nothing! I even try to concatenate the different groups in a string (with CONCAT or with string_agg), but I could not make it.
2
Answers
First create an additional array column
names
that contains the "Name" attributes of the JSON array (t
CTE) and then select those records fromt
whosenames
attribute contains'{TECH.LinuxDevice, TEAM.Monitoring}'
array using@>
operator.DB-Fiddle demo.
You may also try a normalized data desidn with the "Name" attribute (only one per record) in a separate table. That would make things much cleaner and easier.
If you switch your
json
tojsonb
, you can use the@>
containment operator directly:demo at db<>fiddle
To make things fast, you can set up an expression index that indexes your
json
values asjsonb
:Or you can change the type permanently, then build a regular, non-expression GIN index on that:
Storing your data as
jsonb
saves space, speeds things up, simplifies indexing and enables way more functions and operators. Note that there’s a slight difference between the types:Whitespace in key names and their values are considered significant and so is array order, so those won’t be affected.