Why (and How) You Should Manage JSON with SQL
What many people don’t know is that the best way to manage JSON is with a seemingly ancient tool: the SQL language.
Mar 16th, 2022 6:50am by
Featured image via Pixabay
Oracle sponsored this post.
Chris Saxon
Chris is a developer advocate for Oracle Database, where his job is to help you get the best out of it and have fun with SQL. You can find him on Twitter, @ChrisRSaxon, and on his blog, All Things SQL.
- Generate JSON with SQL.
- Convert JSON to relational rows and columns.
- Update JSON documents.
- Search JSON efficiently.
- See the structure of JSON documents.
Generate JSON with SQL
You’ve been tasked with producing an API. It must return department details and an array of the employees working in it. For example:
{
"department": "Accounting",
"employees": [
{
"name": "Higgins, Shelley",
"hireDate": "2002-06-07T00:00:00"
},
{
"name": "Gietz, William",
"hireDate": "2002-06-07T00:00:00"
}
]
}
select json_object (
'department' value d.department_name,
'employees' value json_arrayagg (
json_object (
'name' value last_name || ', ' || first_name,
'hireDate' value hire_date
)
)
)
from hr.departments d
join hr.employees e
on d.department_id = e.department_id
group by d.department_name;
Convert JSON to Relational Rows and Columns
If you are programming, this is hard. But SQL makes this task simple. With a JSON_table, you can unnest JSON arrays, returning a row for each element within them. For example, by passing the document above as a bind variable to this query, SQL can generate a row for each employee:
select j.*
from json_table (
:json_document,
'$' columns (
department path '$.department',
nested path '$.employees[*]'
columns (
name path '$.name',
hire_date path '$.hireDate'
)
)
) j;
DEPARTMENT NAME HIRE_DATE
Accounting Gietz, William 2002-06-07T00:00:00
Accounting Higgins, Shelley 2002-06-07 T00:00:00
Updating JSON Documents
It’s likely you’ll need to change a JSON document after loading it into the database, such as when a customer updates information in a mobile app or if you added a new function to the API. Editing JSON documents can be hard, particularly if you need to make many changes to one document. So, while it’s straightforward to change a single value in the JSON document, such as a customer’s address, changing objects in an array gets tricky. WithJSON_transform, you can add, remove or update many attributes using a single SQL statement. Here’s the SQL to remove the first entry in the employees array, add a new object to the end of that array and update the department name:
json_transform (
:json_document,
remove '$.employees[0]',
append '$.employees' = (
json_object (
'name' value 'Saxon, Chris',
'hireDate' value '2020-01-01T00:00:00'
)
),
replace '$.department' = 'Finance and Accounting'
)
JSON_transform has clauses covering each of these cases. Each clause gives you the choice to ignore an anomaly or raise an exception. These options give you fine-grained control over the change.
With SQL and JSON, combining the employee arrays from two departments into one array is easy. You may be wondering: How do you find these JSON documents?
Search JSON Efficiently
SQL’s simple dot-notation access lets you search JSON without much effort. All you need to do is pass the path to the attribute and the value you’re looking for. For example, this finds all the documents with a department attribute that has the valueFinance:
select * from companies c
where c.department_data.department = 'Finance';
- JSON search index. This indexes the whole document.
- Function-based indexes. These target one attribute in the document.
- Multi-value indexes. These target many elements in an array.
See the Structure of JSON Documents
The free-form nature of JSON is both its biggest strength and its biggest weakness. Once you start storing JSON documents in your database, it’s easy to lose track of what their structure is. The only way to know the structure of a document is to query its attributes. The JSON Data Guide is a function that solves this problem for you. By passing JSON documents to the `JSON_dataguide` function, you can get their schema. If you create a search index, this information becomes available in the database’s data dictionary, which includes the path and data type for every attribute stored in an indexed JSON document. For example, this query returns the structure of a JSON document stored indepartments.department_json:
select json_dataguide (
d.department_json,
dbms_json.format_hierarchical
)
from departments d;
{
"type" : "object",
"o:length" : 256,
"properties" : {
"employees" : {
"type" : "array",
"o:length" : 128,
"o:preferred_column_name" : "employees",
"items" : {
"properties" : {
"name" : {
"type" : "string",
"o:length" : 16,
"o:preferred_column_name" : "name"
},
"hireDate" : {
"type" : "string",
"o:length" : 32,
"o:preferred_column_name" : "hireDate"
}
}
}
},
"department" : {
"type" : "string",
"o:length" : 16,
"o:preferred_column_name" : "department"
}
}
}
Conclusion
Working with large JSON documents can be challenging for every application. No matter how the data is stored, it’s likely you need to map JSON to relational or vice-versa. Oracle SQL has many options to make this easy. This Live SQL script is an online lesson packed with examples showing how these features work. Check it out! For the full rundown on using SQL to manage JSON documents in Oracle Database, read the JSON Developer’s Guide. And if you want your own database to try these out on, sign up for Oracle Cloud Free Tier. You can also check out my free SQL classes on Oracle Dev Gym and my video combining SQL and magic on The Magic of SQL YouTube channel. I hope this article has helped you see why developers fell in love with SQL 40 years ago and how it can make you better at managing JSON docs today.
YOUTUBE.COM/THENEWSTACK
Tech moves fast, don't miss an episode. Subscribe to our YouTube
channel to stream all our podcasts, interviews, demos, and more.