Read our blogs, tips and tutorials
Try our exercises or test your skills
Watch our tutorial videos or shorts
Take a self-paced course
Read our recent newsletters
License our courseware
Book expert consultancy
Buy our publications
Get help in using our site
428 attributed reviews in the last 3 years
Refreshingly small course sizes
Outstandingly good courseware
Whizzy online classrooms
Wise Owl trainers only (no freelancers)
Almost no cancellations
We have genuine integrity
We invoice after training
Review 30+ years of Wise Owl
View our top 100 clients
Search our website
We also send out useful tips in a monthly email newsletter ...
Some other pages relevant to these blogs include:
You can also book hourly online consultancy for your time zone with one of our 7 expert trainers!
|
Using JSON in SQL Server, including the new SQL 2025 functions Part five of an eight-part series of blogs |
|---|
|
SQL Server 2025 introduces a new JSON data type and some new JSON functions - we thought we'd use this as an excuse to create this masterclass on working with JSON in SQL Server
|
In this blog
If you want to extract arrays of data from with JSON it's probably easiest to use OPENJSON to shred data. Here's a quick reminder of what we have so far - a table containing our JSON data of Star Wars characters:

The JSON for the list of characters is in a column called PersonJson.
With this JSON:

The beginning of the JSON listing the characters.
For each row of the tblPerson table (there only is one, as it happens) we want to get a list of all of characters' names and heights from the results section of the JSON. Here's how to do this:
SELECT
f.PersonId,
-- show the list of names and heights for this row
shredded_rows.CharacterName,
shredded_rows.CharacterHeight
FROM
tblPerson AS f
-- for each person, get the JSON containing their results
CROSS APPLY OPENJSON(f.PersonJson, '$.results')
-- and from this extract their name and height
WITH (
CharacterName nvarchar(200) '$.name',
CharacterHeight int '$.height'
) AS shredded_rows;
Here's what this returns for our example:

Had there been a second set of JSON in the table, the characters from this would be listed too.
The way this works is using something very similar to a correlated subquery. For each row in the tblPerson table we open up the JSON stored in the PersonJson column, get the results node, split the contents of the array within this into rows and pick out the name and height properties, giving each an alias. We then show these values in the main query.
Each character in the results node has a subnode called films giving the URLs of the films they've appeared in:

The films for Luke Skywalker, for example. Notice that there's no name for each film object - just a value giving the URL.
You could extend our SQL to show the film URLs for each character:

I wouldn't normally include the columns shown in the red boxes above - I've included these just for reference.
Deep breath! Here's the SQL to show these results:
SELECT
f.PersonId,
-- show the list of names and heights for this row
shredded_rows.CharacterName,
shredded_rows.CharacterHeight,
-- show the list of films as JSON for reference
shredded_rows.FilmList,
-- show all of the URL fields (would normally just
-- show FilmUrls.Value)
FilmUrls.*
FROM
tblPerson AS f
-- for each person, get the JSON containing their results
CROSS APPLY OPENJSON(f.PersonJson, '$.results')
-- and from this extract their name, height and ...
WITH (
CharacterName nvarchar(200) '$.name',
CharacterHeight int '$.height',
-- ... the list of films they were in
FilmList nvarchar(max) '$.films' AS JSON
) AS shredded_rows
-- take the list of films and split it into the
-- individual rows
CROSS APPLY OPENJSON(shredded_rows.FilmList) AS FilmUrls
Here's what this does:
For each row in the tblPerson table (there only is one) ...
... for each character in the results section of the JSON stored in the PersonJSON column, pick out the character's name, height and the list of films, then ...
... for each film in this character's films, split it into the individual rows
The trickiest part of this SQL was getting the data types for this line right:
-- ... the list of films they were in
FilmList nvarchar(max) '$.films' AS JSON
You seem to have to get the data as text and then convert it into JSON!
Some other pages relevant to these blogs include:
You can also book hourly online consultancy for your time zone with one of our 7 expert trainers!
Kingsmoor House
Railway Street
GLOSSOP
SK13 2AA
Landmark Offices
99 Bishopsgate
LONDON
EC2M 3XD
Holiday Inn
25 Aytoun Street
MANCHESTER
M1 3AE
© Wise Owl Business Solutions Ltd 2025. All Rights Reserved.