SQL select from array in JSON - sql

I have a table with a json field with the following json:
[
{
productId: '1',
other : [
otherId: '2'
]
},
{
productId: '3',
other : [
otherId: '4'
]
}
]
I am trying to select the productId and otherId for every array element like this:
select JSON_EXTRACT(items, $.items[].productId) from order;
But this is completely wrong since it takes only the first element in the array
Do I need to write a loop or something?

First of all, the data you show is not valid JSON. It has multiple mistakes that make it invalid.
Here's a demo using valid JSON:
mysql> create table orders ( items json );
mysql> insert into orders set items = '[ { "productId": "1", "other": { "otherId": "2" } }, { "productId": "3", "other" : { "otherId": "4" } } ]'
mysql> SELECT JSON_EXTRACT(items, '$[*].productId') AS productIds FROM orders;
+------------+
| productIds |
+------------+
| ["1", "3"] |
+------------+
If you want each productId on a row by itself as a scalar value instead of a JSON array, you'd have to use JSON_TABLE() in MySQL 8.0:
mysql> SELECT j.* FROM orders CROSS JOIN JSON_TABLE(items, '$[*]' COLUMNS(productId INT PATH '$.productId')) AS j;
+-----------+
| productId |
+-----------+
| 1 |
| 3 |
+-----------+
This is tested in MySQL 8.0.23.
You also tagged your question MariaDB. I don't use MariaDB, and MariaDB has its own incompatible implementation of JSON support, so I can't predict how it will work.

Related

SQL query to run over object of an object with array of data

| some_data |
-------------
| cards: [{"story-elements": [{
"metadata": {
"video-url": "somesite.com/video/x8cse6q?pubtool",
"video-id": "x8cse6q?pubtool"},
"subtype": "abc-video"
}]|
How to filter data from some_data column where cards consists of video-url with query params when subtype is abc-video
select *
from table_name
WHERE ("some_data" #> '{"video-id"}')::varchar like '%?pubtool%';

How can I modify all values that match a condition inside a json array?

I have a table which has a JSON column called people like this:
Id
people
1
[{ "id": 6 }, { "id": 5 }, { "id": 3 }]
2
[{ "id": 2 }, { "id": 3 }, { "id": 1 }]
...and I need to update the people column and put a 0 in the path $[*].id where id = 3, so after executing the query, the table should end like this:
Id
people
1
[{ "id": 6 }, { "id": 5 }, { "id": 0 }]
2
[{ "id": 2 }, { "id": 0 }, { "id": 1 }]
There may be more than one match per row.
Honestly, I didnĀ“t tried any query since I cannot figure out how can I loop inside a field, but my idea was something like this:
UPDATE mytable
SET people = JSON_SET(people, '$[*].id', 0)
WHERE /* ...something should go here */
This is my version
SELECT VERSION()
+-----------------+
| version() |
+-----------------+
| 10.4.22-MariaDB |
+-----------------+
If the id values in people are unique, you can use a combination of JSON_SEARCH and JSON_REPLACE to change the values:
UPDATE mytable
SET people = JSON_REPLACE(people, JSON_UNQUOTE(JSON_SEARCH(people, 'one', 3)), 0)
WHERE JSON_SEARCH(people, 'one', 3) IS NOT NULL
Note that the WHERE clause is necessary to prevent the query replacing values with NULL when the value is not found due to JSON_SEARCH returning NULL (which then causes JSON_REPLACE to return NULL as well).
If the id values are not unique, you will have to rely on string replacement, preferably using REGEXP_REPLACE to deal with possible differences in spacing in the values (and also avoiding replacing 3 in (for example) 23 or 34:
UPDATE mytable
SET people = REGEXP_REPLACE(people, '("id"\\s*:\\s*)2\\b', '\\14')
Demo on dbfiddle
As stated in the official documentation, MySQL stores JSON-format strings in a string column, for this reason you can either use the JSON_SET function or any string function.
For your specific task, applying the REPLACE string function may suit your case:
UPDATE
mytable
SET
people = REPLACE(people, CONCAT('"id": ', 3, ' '), CONCAT('"id": ',0, ' '))
WHERE
....;

How to pretty format JSON in Oracle?

I wanted to know if there is any way to format a JSON in Oracle (as does this web site example)
In XML I used:
SELECT XMLSERIALIZE(Document XMLTYPE(V_RESPONSE) AS CLOB INDENT SIZE = 2)
INTO V_RESPONSE
FROM DUAL;
And it works very well.
With Oracle 12c, you can use the JSON_QUERY() function with the RETURNING ... PRETTY clause :
PRETTY : Specify PRETTY to pretty-print the return character string by inserting newline characters and indenting
Expression :
JSON_QUERY(js_value, '$' RETURNING VARCHAR2(4000) PRETTY)
Demo on DB Fiddle :
with t as (select '{"a":1, "b": [{"b1":2}, {"b2": "z"}]}' js from dual)
select json_query(js, '$' returning varchar2(4000) pretty) pretty_js, js from t;
Yields :
PRETTY_JS | JS
--------------------------|----------------------------------------
{ | {"a":1, "b": [{"b1":2}, {"b2": "z"}]}
"a" : 1, |
"b" : |
[ |
{ |
"b1" : 2 |
}, |
{ |
"b2" : "z" |
} |
] |
} |
When you're lucky enough to get to Oracle Database 19c, there's another option for pretty printing: JSON_serialize.
This allows you to convert JSON between VARCHAR2/CLOB/BLOB. And includes a PRETTY clause:
with t as (
select '{"a":1, "b": [{"b1":2}, {"b2": "z"}]}' js
from dual
)
select json_serialize (
js returning varchar2 pretty
) pretty_js,
js
from t;
PRETTY_JS JS
{ {"a":1, "b": [{"b1":2}, {"b2": "z"}]}
"a" : 1,
"b" :
[
{
"b1" : 2
},
{
"b2" : "z"
}
]
}

Json Querying using SQL Server

I have a Json data stored in SQL server:
{
"group":{
"operator":"AND",
"rules":[
{
"condition":"=",
"field":"F1",
"table":"ATT",
"data":"TEST",
"readOnly":false,
"hidden":false,
"$$hashKey":"005"
},
{
"condition":"=",
"field":"CLASS",
"table":"OBJ",
"data":"A1",
"readOnly":false,
"hidden":false,
"$$hashKey":"008"
},
{
"group":{
"operator":"AND",
"rules":[
{
"condition":"=",
"field":"F1",
"table":"ATT",
"data":"TEST2",
"readOnly":false,
"hidden":false,
"$$hashKey":"00D"
},
{
"condition":"=",
"field":"F1",
"table":"ATT",
"data":"TEST3",
"readOnly":false,
"hidden":false,
"$$hashKey":"00G"
}
]
},
"table":"",
"$$hashKey":"009"
}
]
}
}
How can I get the count of the element field having value =F1 using SQL?
DECLARE #json NVARCHAR(MAX) = '{"group":{
"operator":"AND",
"rules":
[{"condition":"=",
"field":"F1",
"table":"ATT",
"data":"TEST",
"readOnly":false,
"hidden":false,
"$$hashKey":"005"},
{"condition":"=",
"field":"BANKID",
"table":"ATT",
"data":"A1",
"readOnly":false,
"hidden":false,
"$$hashKey":"008"}]}}';
SELECT COUNT(*)
FROM OPENJSON(#json, '$.group.rules')
WHERE JSON_VALUE(value, '$.field') = 'F1'
You have a table, you say? CROSS APPLY is your friend:
SELECT T.[data], rules.F1_count
FROM T CROSS APPLY (
SELECT COUNT(*) AS F1_count
FROM OPENJSON(jsonData, '$.group.rules')
WHERE JSON_VALUE(value, '$.field') = 'F1'
) AS rules
Try this ->
Select Count(*)
From mytable
WHERE JSON_VALUE(Serialized, '$.field')="F1"
As an advice JSON data should not be stored it self. You should make tables and columns depending on the data you are storing. Maybe make a database called group, with a table called operator, which would have three columns, operator, rule and rule value. So it would look something like this:
Operator Rule RuleValue
-------- ----------- ---------
| #1 | condition | = |
| #1 | field | f1 |
| #1 | table | ATT |
| #2 | data | test |
You can change the table to your needs but remember JSON and XML is a way of storing data in files. So when storing data in database, you shouldn't store it in XMl or JSON

Postgres WHERE array contains empty string

I'm trying to do select * from demo where demojson->'sub'->'item' = array("") but this doesn't work. I'd like to find the following
All rows where .sub.item in the JSON column is an array containing exactly one empty string ([""])
All rows where .sub.item in the JSON column is an array that may contain more than one item, but at least one of the items is an empty string. (["not empty", "also not empty", ""])
demojson column could contain for example
{
"key": "value",
"sub": {
"item": [""]
}
}
Have you tried
SELECT * from demo
WHERE demojson->'sub'->>'item' = '[""]';
Here ->> operator allows to get JSON object field as text.
And another solution
SELECT * from demo
WHERE json_array_length(demojson->'sub'->'item') = 1 AND
demojson->'sub'->'item'->>0 = '';
Here ->> operators allows to get JSON first array element as text.
Due JSONLint doesn't validate the supplied text example, I've used the next:
CREATE TABLE info (id int, j JSON);
insert into info values
(1, '{"key":"k1", "sub": {"item":["i1","i2"]}}'),
(2, '{"key":"k2", "sub": {"item":[""]}}'),
(3, '{"key":"k3", "sub": {"item":["i2","i3"]}}');
Using the where clause in this way, it works:
select * from info
where j->'sub'->>'item' = '[""]';
+----+------------------------------------+
| id | j |
+----+------------------------------------+
| 2 | {"key":"k2", "sub": {"item":[""]}} |
+----+------------------------------------+
Can check it here: http://rextester.com/VEPY57423
Try the following:
SELECT * FROM demo
WHERE demojson->'sub'->'item' = to_jsonb(ARRAY['']);