SQL find elements is in JSON array column - sql

Hello i have a column table who contains json array with tags in it, I try to find a way to select result who contain some of values in it :
ID
tags
1
["test01"]
2
["test02","test03"]
I try to used JSON_QUERY AND JSON_VALUE():
SELECT *
FROM table_tags
WHERE JSON_QUERY(tags,'$') IN ('test01', 'test02')
return nothing
but with json_value on the first array element [0]
SELECT *
FROM table_tags
WHERE JSON_VALUE(tags,'$[0]') IN ('test01', 'test02')
it return the first one with test01
ID
tags
1
["test01"]
i need to find a way to iterate through json_value tags to find all tags in ('test01', 'test02')

You need an OPENJSON() call to parse the stored JSON array. The result is a table with columns key, value and type and in the value column is each element from the parsed JSON array. The column data type is nvarchar(max) with the same collation as tags column collation.
SELECT *
FROM (VALUES
(1, '["test01"]'),
(2, '["test02","test03"]')
) table_tags (id, tags)
WHERE EXISTS (
SELECT 1 FROM OPENJSON(tags) WHERE [value] IN ('test01', 'test02')
)

Related

Transform JSON element to SQL Table Format

This question is in relation to my previous problem which was solved.
Link to Previous Problem
Now I need to access columns and values of the Tag "GetCustomReportResult" and transform into a SQL Table format.
The JSON String is actually stored in a column in a SQL Table as seen below and I am trying to transform the elements in the tag "GetCustomReportResult" in a table format with columns and values for each of the "ApplicationID":
Here is what I was trying to access the columns and values within the Tag "GetCustomReportResult":
SELECT
y.cijreport,
y.ApplicationId,
JSON_VALUE(x.value, '$.CIP') as CIP,
JSON_VALUE(x.value, '$.CIQ') as CIQ
--other fields
FROM table as y
CROSS APPLY OPENJSON (cijreport) as x
where cijreport is not null
I now get this error when I execute:
Msg 13609, Level 16, State 2, Line 1 JSON text is not properly formatted. Unexpected character 'o' is found at position 0.
Firstly, you are missing the JSON path '$.data.response'.
Next, you can't use JSON_VALUE on a whole object, it's only good for scalar values. You can either use JSON_QUERY:
SELECT
y.cijreport,
y.ApplicationId,
JSON_QUERY(x.value, '$.CIP') as CIP,
JSON_QUERY(x.value, '$.CIQ') as CIQ, x.VALUE
--other fields
FROM YourTable as y
CROSS APPLY OPENJSON (cijreport, '$.data.response') as x;
Or you can specify property names in OPENJSON
SELECT
y.cijreport,
y.ApplicationId,
x.CIP,
x.CIQ
--other fields
FROM YourTable as y
CROSS APPLY OPENJSON (cijreport, '$.data.response')
WITH (
CIP nvarchar(max) AS JSON,
CIQ nvarchar(max) AS JSON
) AS x;
db<>fiddle
Note that the where cijreport is not null filter is not necessary, because CROSS APPLY OPENJSON will return 0 rows in such a case, and CROSS APPLY acts like an inner join.

Compare two arrays in PostgreSQL

I have a table in postgres with a value column that contains string arrays. My objective is to find all arrays that contain any of the following strings: {'cat', 'dog'}
id value
1 {'dog', 'cat', 'fish'}
2 {'elephant', 'mouse'}
3 {'lizard', 'dog', 'parrot'}
4 {'bear', 'bird', 'cat'}
The following query uses ANY() to check if 'dog' is equal to any of the items in each array and will correctly return rows 1 and 3:
select * from mytable where 'dog'=ANY(value);
I am trying to find a way to search value for any match in an array of strings. For example :
select * from mytable where ANY({'dog', 'cat'})=ANY(value);
Should return rows 1, 3, and 4. However, the above code throws an error. Is there a way to use the ANY() clause on the left side of this equation? If not, what would be the workaround to check if any of the strings in an array are in value?
You can use && operator to find out whether two array has been overlapped or not. It will return true only if at least one element from each array match.
Schema and insert statements:
create table mytable (id int, value text[]);
insert into mytable values (1,'{"dog", "cat", "fish"}');
insert into mytable values (2,'{"elephant", "mouse"}');
insert into mytable values (3,'{"lizard", "dog", "parrot"}');
insert into mytable values (4,'{"bear", "bird", "cat"}');
Query:
select * from mytable where array['dog', 'cat'] && (value);
Output:
id
value
1
{dog,cat,fish}
3
{lizard,dog,parrot}
4
{bear,bird,cat}
db<>fiddle here

Oracle search array within JSON values?

I have the following stored in an Oracle database as JSON:
{
value: [1,2,3]
}
The value can be of any type (strings, integers or arrays). How would I query if the type is array and if it contains a certain value?
In pseudocode:
SELECT * FROM TABLE WHERE COLUMN_NAME.value CONTAINS 2
I can see how to query strings using Oracle functions such as json_query but cannot see how to run this specific type of query without selecting all data and searching on the client.
You may use JSON_TABLE in the FROM, defining the columns and then use it in where clause to filter rows.
--Test data
with t (id,j)
as
( select 1, TO_CLOB(
'{
value : [1,2,3]
}') FROM DUAL
)
--Test data ends--
select t.id,tbl.val FROM t cross join
json_table(j,'$.value[*]' columns (val varchar2(100) path '$') ) as tbl
where tbl.val = 2
ID VAL
------ -------
1 2

JSONB array contains like OR and AND operators

Consider a table temp (jsondata jsonb)
Postgres provides a way to query jsonb array object for contains check using
SELECT jsondata
FROM temp
WHERE (jsondata->'properties'->'home') ? 'football'
But, we can't use LIKE operator for array contains. One way to get LIKE in the array contains is using -
SELECT jsondata
FROM temp,jsonb_array_elements_text(temp.jsondata->'properties'->'home')
WHERE value like '%foot%'
OR operation with LIKE can be achieved by using -
SELECT DISTINCT jsondata
FROM temp,jsonb_array_elements_text(temp.jsondata->'properties'->'home')
WHERE value like '%foot%' OR value like 'stad%'
But, I am unable to perform AND operation with LIKE operator in JSONB array contains.
After unnesting the array with jsonb_array_elements() you can check values meeting one of the conditions and sum them in groups by original rows, example:
drop table if exists temp;
create table temp(id serial primary key, jsondata jsonb);
insert into temp (jsondata) values
('{"properties":{"home":["football","stadium","16"]}}'),
('{"properties":{"home":["football","player","16"]}}'),
('{"properties":{"home":["soccer","stadium","16"]}}');
select jsondata
from temp
cross join jsonb_array_elements_text(temp.jsondata->'properties'->'home')
group by jsondata
-- or better:
-- group by id
having sum((value like '%foot%' or value like 'stad%')::int) = 2
jsondata
---------------------------------------------------------
{"properties": {"home": ["football", "stadium", "16"]}}
(1 row)
Update. The above query may be expensive with a large dataset. There is a simplified but faster solution. You can cast the array to text and apply like to it, e.g.:
select jsondata
from temp
where jsondata->'properties'->>'home' like all('{%foot%, %stad%}');
jsondata
---------------------------------------------------------
{"properties": {"home": ["football", "stadium", "16"]}}
(1 row)
I have the following, but it was a bit fiddly. There's probably a better way but this is working I think.
The idea is to find the matching JSON array entries, then collect the results. In the join condition we check the "matches" array has the expected number of entries.
CREATE TABLE temp (jsondata jsonb);
INSERT INTO temp VALUES ('{"properties":{"home":["football","stadium",16]}}');
SELECT jsondata FROM temp t
INNER JOIN LATERAL (
SELECT array_agg(value) AS matches
FROM jsonb_array_elements_text(t.jsondata->'properties'->'home')
WHERE value LIKE '%foo%' OR value LIKE '%sta%'
LIMIT 1
) l ON array_length(matches, 1) = 2;
jsondata
-------------------------------------------------------
{"properties": {"home": ["football", "stadium", 16]}}
(1 row)
demo: db<>fiddle
I would cast the array into text. Then you are able to search for keywords with every string operator.
Disadvantage: because it was an array the text contains characters like braces and commas. So it's not that simple to search for keyword with a certain beginning (ABC%): You always have to search like %ABC%
SELECT jsondata
FROM (
SELECT
jsondata,
jsondata->'properties'->>'home' as a
FROM
temp
)s
WHERE
a LIKE '%stad%' AND a LIKE '%foot%'

How to search SQL column containing JSON array

I have a SQL column that has a single JSON array:
{"names":["Joe","Fred","Sue"]}
Given a search string, how can I use SQL to search for a match in the names array? I am using SQL 2016 and have looked at JSON_QUERY, but don't know how to search for a match on a JSON array. Something like below would be nice.
SELECT *
FROM table
WHERE JSON_QUERY(column, '$.names') = 'Joe'
For doing a search in a JSON array, one needs to use OPENJSON
DECLARE #table TABLE (Col NVARCHAR(MAX))
INSERT INTO #table VALUES ('{"names":["Joe","Fred","Sue"]}')
SELECT * FROM #table
WHERE 'Joe' IN ( SELECT value FROM OPENJSON(Col,'$.names'))
or as an alternative, one can use it with CROSS APPLY.
SELECT * FROM
#table
CROSS APPLY OPENJSON(Col,'$.names')
WHERE value ='Joe'
Postgres syntax
When you know the key that holds the data:
SELECT column_name from table_name where column_name->>'key' LIKE '%QUERYSTRING%';
When you don't know the key that holds the data:
SELECT column_name from table_name where column_name::text LIKE '%QUERYSTRING%';
It's very simple , can be easily done using JSON_CONTAINS() function.
SELECT * FROM table
where JSON_CONTAINS(column, 'joe','$.name');
You can search for a match on a JSON array via below query:
SELECT JSON_EXTRACT(COLUMN, "$.names") AS NAME
FROM TABLE JSON_EXTRACT(COLUMN, "$.names") != ""
Replace the TABLE with your table name and COLUMN with the column name in the table.
the key I have mentioned name as it was there in your question.
Just want to add to the existing answers a simple solution how you can check if array inside json contains a value:
DECLARE #Json NVARCHAR(max) = '{"names":["Joe","Fred","Sue"]}'
IF EXISTS (SELECT value FROM OPENJSON(#Json,'$.names') WHERE value = 'Joe')
PRINT 'Array contains "Joe"'
ELSE
PRINT 'Array does not contain "Joe"'