This is my json data in one of the oracle sql columns "jsoncol" in a table named "jsontable"
{
"Company": [
{
"Info": {
"Address": "123"
},
"Name": "ABC",
"Id": 999
},
{
"Info": {
"Address": "456"
},
"Name": "XYZ",
"Id": 888
}
]
}
I am looking for an UPDATE query to update all the value of "Name" with a new value based on a particular "Id" value.
Thanks in advance
From Oracle 19, you can use JSON_MERGEPATCH:
UPDATE jsontable j
SET jsoncol = JSON_MERGEPATCH(
jsoncol,
(
SELECT JSON_OBJECT(
KEY 'Company'
VALUE JSON_ARRAYAGG(
CASE id
WHEN 999
THEN JSON_MERGEPATCH(
json,
'{"Name":"DEF"}'
)
ELSE json
END
FORMAT JSON
RETURNING CLOB
)
FORMAT JSON
RETURNING CLOB
)
FROM jsontable jt
CROSS APPLY JSON_TABLE(
jt.jsoncol,
'$.Company[*]'
COLUMNS(
json VARCHAR2(4000) FORMAT JSON PATH '$',
id NUMBER PATH '$.Id'
)
)
WHERE jt.ROWID = j.ROWID
)
)
Which, for the sample data:
CREATE TABLE jsontable (
jsoncol CLOB CHECK (jsoncol IS JSON)
);
INSERT INTO jsontable (jsoncol)
VALUES ('{
"Company": [
{
"Info": {
"Address": "123"
},
"Name": "ABC",
"Id": 999
},
{
"Info": {
"Address": "456"
},
"Name": "XYZ",
"Id": 888
}
]
}');
Then after the UPDATE, the table contains:
JSONCOL
{"Company":[{"Info":{"Address":"123"},"Name":"DEF","Id":999},{"Info":{"Address":"456"},"Name":"XYZ","Id":888}]}
db<>fiddle here
You can use REPLACE() within JSON_TABLE() function in order to update the value of the Name(from ABC to DEF) for a specific Id value(999) such as
UPDATE jsontable jt0
SET jsoncol = ( SELECT REPLACE(jsoncol,jt.name,'DEF')
FROM jsontable j,
JSON_TABLE(jsoncol,
'$' COLUMNS(NESTED PATH '$.Company[*]'
COLUMNS(
name VARCHAR2 PATH '$.Name',
id INT PATH '$.Id'
)
)
) jt
WHERE jt.id = 999
AND j.id = jt0.id )
for the DB version prior to 19 provided that the identity values(id) of the table and of the JSON values are unique throughout the table and each individual JSON value, respectively.
Demo
Related
Is there a way to update the data retrieved from the below select (in this case, change "MS220" to something else)? It's difficult enough to do select from JSON in some cases. I'm not sure how to update just a single element.
CREATE TABLE JData (
JsonData nvarchar(max)
)
INSERT INTO JData
(JsonData)
VALUES
('[
{
"Categories": [
{
"QuerySourceNames": [
"QAsset"
],
"Id": "eceae85a-ffc6-49f4-8f6a-78ce2b4b274e",
"Name": "emsdba"
}
],
"Id": "525b4f07-0f67-43ac-8070-a0e6c1ceb1b9",
"Name": "MS220"
}
]')
SELECT
ParamName
FROM [dbo].[JData] jsonData
CROSS APPLY OPENJSON (jsonData)
WITH
(
Categories nvarchar(max) AS json,
Id uniqueidentifier,
ParamName varchar(10) '$.Name'
);
Try JSON_MODIFY() with the path '$[0].Name'
UPDATE d
SET jsonData = JSON_MODIFY(jsonData, '$[0].Name', 'New Value')
FROM [dbo].[JData] d
Results:
[
{
"Categories": [
{
"QuerySourceNames": [
"QAsset"
],
"Id": "eceae85a-ffc6-49f4-8f6a-78ce2b4b274e",
"Name": "emsdba"
}
],
"Id": "525b4f07-0f67-43ac-8070-a0e6c1ceb1b9",
"Name": "New Value"
}
]
db<>fiddle here
I have JSON as below,
{
"value": [
{
"id": "123",
"createdDateTime": "2021-09-17T14:15:18Z"
},
{
"id": "124",
"createdDateTime": "2022-09-17T14:15:18Z"
}
]
}
am trying to get the output as 2 separate records and store it in clob column(values), any help would be appreciated.
values
{"id": "123","createdDateTime": "2021-09-17T14:15:18Z"}
{"id": "123","createdDateTime": "2021-09-17T14:15:18Z"}
You can use JSON_TABLE:
SELECT j.value
FROM table_name t
CROSS APPLY JSON_TABLE(
t.json_value,
'$.value[*]'
COLUMNS
value VARCHAR2(4000) FORMAT JSON PATH '$'
) j
Which, for the sample data:
CREATE TABLE table_name (json_value CLOB CHECK (json_value IS JSON));
INSERT INTO table_name (json_value)
VALUES ('{"value":[{
"id": "123",
"createdDateTime": "2021-09-17T14:15:18Z"
},
{
"id": "124",
"createdDateTime": "2022-09-17T14:15:18Z"
}]}')
Outputs:
VALUE
{"id":"123","createdDateTime":"2021-09-17T14:15:18Z"}
{"id":"124","createdDateTime":"2022-09-17T14:15:18Z"}
db<>fiddle here
I have a table that contains json data that I need to unpick and store in a relational DB. I am using an Oracle DB 19.0 and have created the following table:
CREATE TABLE J_PAGE
(
PK_PAGE_ID NUMBER ( 10 , 0 )
, FK_RESP_ID NUMBER ( 10 , 0 ) DEFAULT -1
, CL_PAGE_ID NUMBER ( 10 , 0 ) DEFAULT -1
, CL_RESP CLOB CONSTRAINT CK_PAGE_01 CHECK ( CL_RESP IS JSON )
, CL_DT DATE DEFAULT SYSDATE
) ;
The column CL_RESP is a clob value that returns the response from a call to UTL_HTTP.GET_RESPONSE.
{
"count": 2,
"results": [
{
"key": "stories",
"id": "10000"
},
{
"key": "stories",
"id": "10001"
}
],
"stories": {
"10000": {
"title": "story1",
"description": null,
"start_date": "2020-04-01",
"id": "10001"
},
"10001": {
"title": "story2",
"description": null,
"start_date": null,
"id": "10001"
}
},
"meta": {
"count": 2,
"page_count": 1,
"page_number": 1,
"page_size": 20
}
}
I need to extract the contents of the "stories" element but I'm getting stuck where the next element doesn't have a static name.
I know I can do the following to return 1 row using story 10001...
SELECT
page.CL_RESP.stories."10001".title[*] CL_TITLE
FROM
J_PAGE page ;
But I need all stories so perhaps a wildcard in place of 10001?
SELECT
page.CL_RESP.stories.*.title[*] CL_TITLE
FROM
J_PAGE page ;
Can anyone help?
Solved it.
SELECT
t.*
FROM
J_PAGE o,
JSON_TABLE ( o.CL_RESP , '$.stories.*'
COLUMNS (
CL_TITLE VARCHAR2 PATH '$.title'
, CL_DESC VARCHAR2 PATH '$.description'
, CL_START_DT TIMESTAMP PATH '$.start_date'
, CL_ID NUMBER PATH '$.id'
)
) t ;
Having this
create table departments_json (
department_id
integer
NOT NULL
CONSTRAINT departments_json__id__pk PRIMARY KEY,
department_data
CLOB
NOT NULL
CONSTRAINT departments_json__data__chk CHECK ( department_data IS JSON )
);
insert into departments_json
json values ( 110, '{
"department": "Accounting",
"employees": [
{
"name": "Higgins, Shelley",
"job": "Accounting Manager",
"hireDate": "2002-06-07T00:00:00"
},
{
"name": "Gietz, William",
"job": "Public Accountant",
"hireDate": "2002-06-07T00:00:00"
}
]
}'
);
And the new json :
{
"employees": [
{
"name": "Chen, John",
"job": "Accountant",
"hireDate": "2005-09-28T00:00:00"
},
{
"name": "Greenberg, Nancy",
"job": "Finance Manager",
"hireDate": "2002-08-17T00:00:00"
},
{
"name": "Urman, Jose Manuel",
"job": "Accountant",
"hireDate": "2006-03-07T00:00:00"
}
]
}
After this POST the response help me a lot. But now is time to update the column department_data with the new json. i'm using this query:
update departments_json d
set d.department_data =
WITH employees ( json ) AS (
SELECT j.json
FROM departments_json d
CROSS APPLY JSON_TABLE(
d.department_data,
'$.employees[*]'
COLUMNS (
json CLOB FORMAT JSON PATH '$'
)
) j
WHERE d.department_id = 110
UNION ALL
SELECT j.json
FROM JSON_TABLE(
'{
employees: [
{
name: Chen, John,
job: Accountant,
hireDate: 2005-09-28T00:00:00
},
{
name: Greenberg, Nancy,
job: Finance Manager,
hireDate: 2002-08-17T00:00:00
},
{
name: Urman, Jose Manuel,
job: Accountant,
hireDate: 2006-03-07T00:00:00
}
]
}',
'$.employees[*]'
COLUMNS (
json CLOB FORMAT JSON PATH '$'
)
) j
)JSON_MERGEPATCH(
d.department_data,
(
SELECT JSON_OBJECT(
KEY 'employees'
VALUE JSON_ARRAYAGG( json FORMAT JSON RETURNING CLOB )
FORMAT JSON
)
FROM employees
)
)
WHERE d.department_id = 110;
But i got this error, and i don' know where is wrong
Error :
Error en la línea de comandos : 3 Columna : 5
Informe de error -
Error SQL: ORA-00936: falta una expresión
00936. 00000 - "missing expression"
*Cause:
*Action:
What is wrong, i'm following this step: LINK
NOTE: this is how my table looks like:
UPDATE
After apply MP0 suggest, this is how my query looks like (two options)
But the problem is that i have this error:
ORA-40478: output value too large (maximum: 4000)
You can use:
UPDATE departments_json
SET department_data = JSON_MERGEPATCH(
department_data,
(
SELECT JSON_OBJECT(
KEY 'employees'
VALUE JSON_ARRAYAGG( json FORMAT JSON RETURNING CLOB )
FORMAT JSON RETURNING CLOB
)
FROM (
SELECT j.json
FROM departments_json d
CROSS APPLY JSON_TABLE(
d.department_data,
'$.employees[*]'
COLUMNS (
json CLOB FORMAT JSON PATH '$'
)
) j
WHERE d.department_id = 110
UNION ALL
SELECT j.json
FROM JSON_TABLE(
'{
"employees": [
{
"name": "Chen, John",
"job": "Accountant",
"hireDate": "2005-09-28T00:00:00"
},
{
"name": "Greenberg, Nancy",
"job": "Finance Manager",
"hireDate": "2002-08-17T00:00:00"
},
{
"name": "Urman, Jose Manuel",
"job": "Accountant",
"hireDate": "2006-03-07T00:00:00"
}
]
}',
'$.employees[*]'
COLUMNS (
json CLOB FORMAT JSON PATH '$'
)
) j
)
)
RETURNING CLOB
)
WHERE department_id = 110;
Outputs:
DEPARTMENT_ID | DEPARTMENT_DATA
------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
110 | {"department":"Accounting","employees":[{"name":"Higgins, Shelley","job":"Accounting Manager","hireDate":"2002-06-07T00:00:00"},{"name":"Gietz, William","job":"Public Accountant","hireDate":"2002-06-07T00:00:00"},{"name":"Chen, John","job":"Accountant","hireDate":"2005-09-28T00:00:00"},{"name":"Greenberg, Nancy","job":"Finance Manager","hireDate":"2002-08-17T00:00:00"},{"name":"Urman, Jose Manuel","job":"Accountant","hireDate":"2006-03-07T00:00:00"}]}
db<>fiddle here
Update
There are a couple of things wrong with your code:
The JSON_MERGEPATCH needs to wrap around the WITH ... SELECT statement as the output from that statement should be the second argument of JSON_MERGEPATCH; and
Your JSON is invalid as it is missing all the double quotes around the identifiers and the strings.
If you fix that then your code would also work:
update departments_json d
set d.department_data = JSON_MERGEPATCH(
d.department_data,
( -- Start of second argument of JSON_MERGEPATCH
WITH employees ( json ) AS (
SELECT j.json
FROM departments_json d
CROSS APPLY JSON_TABLE(
d.department_data,
'$.employees[*]'
COLUMNS (
json CLOB FORMAT JSON PATH '$'
)
) j
WHERE d.department_id = 110
UNION ALL
SELECT j.json
FROM JSON_TABLE(
'{
"employees": [
{
"name": "Chen, John",
"job": "Accountant",
"hireDate": "2005-09-28T00:00:00"
},
{
"name": "Greenberg, Nancy",
"job": "Finance Manager",
"hireDate": "2002-08-17T00:00:00"
},
{
"name": "Urman, Jose Manuel",
"job": "Accountant",
"hireDate": "2006-03-07T00:00:00"
}
]
}',
'$.employees[*]'
COLUMNS (
json CLOB FORMAT JSON PATH '$'
)
) j
)
SELECT JSON_OBJECT(
KEY 'employees'
VALUE JSON_ARRAYAGG( json FORMAT JSON RETURNING CLOB )
FORMAT JSON RETURNING CLOB
)
FROM employees
) -- End of second argument of JSON_MERGEPATCH
RETURNING CLOB
)
WHERE d.department_id = 110;
db<>fiddle here
I have a simple query in my database:
SELECT id, name FROM users FOR JSON AUTO, ROOT('users')
This returns the following JSON:
{
"users": [
{"id": "1", "name": "John"}
{"id": "2", "name": "Mike"}
]
}
I want to have the return with the following format:
{
"users": {
"list": [
{"id": "1", "name": "John"}
{"id": "2", "name": "Mike"}
]
}
}
Can I do this on SQL level by simply changing the query?
You may try with this:
Table:
CREATE TABLE users (
id varchar(1),
[name] varchar(50)
)
INSERT INTO users
(id, [name])
VALUES
('1', 'John'),
('2', 'Mike')
Statement:
SELECT users = (SELECT id, name FROM users FOR JSON AUTO, ROOT('list'))
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
Result:
{"users":{"list":[{"id":"1","name":"John"},{"id":"2","name":"Mike"}]}}