Two of the many T-SQL functions available in SQL Server are JSON_QUERY()
and JSON_VALUE()
. These functions can be used to extract data from JSON documents.
Their general syntax is similar, and at first glance, you might think they do exactly the same thing, but they don’t. There’s definitely a place for both functions when working with JSON and SQL Server.
This article looks at the difference between JSON_QUERY()
and JSON_VALUE()
.
The Difference
These two functions have slightly different definitions, a slightly different syntax, and their return values are slightly different.
Definitions
Here’s how the two functions are defined:
JSON_QUERY()
- Extracts an object or an array from a JSON string.
JSON_VALUE()
- Extracts a scalar value from a JSON string.
So the difference between these two functions is what they extract. One extracts an object or an array, the other extracts a scalar value.
Syntax Differences
Another difference is in the syntax:
JSON_QUERY ( expression [ , path ] ) JSON_VALUE ( expression , path )
Look at the JSON_QUERY()
syntax. Those square brackets around the path
argument mean that it’s an optional argument. That’s because this function can return a whole JSON document if required.
However, the path argument is a required argument when using the JSON_VALUE()
function. So you must provide both arguments when using this function.
Return Values
And one more difference is in their return values.
JSON_QUERY()
returns a JSON fragment of typenvarchar(max)
JSON_VALUE()
returns a single text value of typenvarchar(4000)
Example 1 – Extract a Scalar Value
Here’s an example to demonstrate the difference between these functions when trying to extract a scalar value.
SELECT JSON_VALUE('{"Name": "Homer"}', '$.Name') AS 'JSON_VALUE', JSON_QUERY('{"Name": "Homer"}', '$.Name') AS 'JSON_QUERY';
Result:
+--------------+--------------+ | JSON_VALUE | JSON_QUERY | |--------------+--------------| | Homer | NULL | +--------------+--------------+
So both functions are trying to extract the same value from the JSON document, but only one succeeds: JSON_VALUE()
. This is because the value they’re trying to extract is a scalar value. Basically, a scalar value is one unit of data. It could be a string of text or a number. But it can’t be an object or an array.
Example 2 – Extract an Array
In this example, both functions try to extract a whole array.
DECLARE @data NVARCHAR(4000) SET @data=N'{ "Suspect": { "Name": "Homer Simpson", "Hobbies": ["Eating", "Sleeping", "Base Jumping"] } }' SELECT JSON_VALUE(@data,'$.Suspect.Hobbies') AS 'JSON_VALUE', JSON_QUERY(@data,'$.Suspect.Hobbies') AS 'JSON_QUERY';
Result:
+--------------+----------------------------------------+ | JSON_VALUE | JSON_QUERY | |--------------+----------------------------------------| | NULL | ["Eating", "Sleeping", "Base Jumping"] | +--------------+----------------------------------------+
In this case, only the JSON_QUERY()
function succeeds.
Example 3 – Extract an Array Item
This example is similar to the previous one, except that instead of trying to extract the whole array, we only want a single item from the array.
DECLARE @data NVARCHAR(4000) SET @data=N'{ "Suspect": { "Name": "Homer Simpson", "Hobbies": ["Eating", "Sleeping", "Base Jumping"] } }' SELECT JSON_VALUE(@data,'$.Suspect.Hobbies[2]') AS 'JSON_VALUE', JSON_QUERY(@data,'$.Suspect.Hobbies[2]') AS 'JSON_QUERY';
Result:
+--------------+--------------+ | JSON_VALUE | JSON_QUERY | |--------------+--------------| | Base Jumping | NULL | +--------------+--------------+
So this time JSON_VALUE()
is the winner.
Example 4 – Extract an Object
Let’s try for a whole object.
DECLARE @data NVARCHAR(4000) SET @data=N'{ "Suspect": { "Name": "Homer Simpson", "Hobbies": ["Eating", "Sleeping", "Base Jumping"] } }' SELECT JSON_VALUE(@data,'$.Suspect') AS 'JSON_VALUE', JSON_QUERY(@data,'$.Suspect') AS 'JSON_QUERY';
Result:
+--------------+--------------+ | JSON_VALUE | JSON_QUERY | |--------------+--------------| | NULL | { "Name": "Homer Simpson", "Hobbies": ["Eating", "Sleeping", "Base Jumping"] } | +--------------+--------------+
And JSON_QUERY()
wins.
(Excuse the formatting, this is how my MSSQL command line tool returns the results).
Example 5 – Extract the Whole JSON Document
Let’s try for the whole JSON document.
DECLARE @data NVARCHAR(4000) SET @data=N'{ "Cities": [ { "Name": "Kabul", "CountryCode": "AFG", "District": "Kabol", "Population": 1780000 }, { "Name": "Qandahar", "CountryCode": "AFG", "District": "Qandahar", "Population": 237500 } ] }' SELECT JSON_VALUE(@data, '$') AS 'JSON_VALUE', JSON_QUERY(@data, '$') AS 'JSON_QUERY';
Result:
+--------------+--------------+ | JSON_VALUE | JSON_QUERY | |--------------+--------------| | NULL | { "Cities": [ { "Name": "Kabul", "CountryCode": "AFG", "District": "Kabol", "Population": 1780000 }, { "Name": "Qandahar", "CountryCode": "AFG", "District": "Qandahar", "Population": 237500 } ] } | +--------------+--------------+
So JSON_QUERY()
is the only one that can return the whole document.
Example 6 – Omit the Path
Another difference between these two functions is that, the path argument is optional when using JSON_QUERY()
. If you omit this, the whole JSON document is returned.
You can’t omit this argument when using JSON_VALUE()
, as it is a required argument. This is probably due to the fact that the function can only return a scalar value. If the first argument only consisted of a scalar value, it wouldn’t be valid JSON.
Anyway, here’s an example of omitting the path argument from JSON_QUERY()
:
SELECT JSON_QUERY('{"Name": "Homer"}') AS 'Result';
Result:
+-------------------+ | Result | |-------------------| | {"Name": "Homer"} | +-------------------+
And here’s what happens if we try that trick with JSON_VALUE()
:
SELECT JSON_VALUE('{"Name": "Homer"}') AS 'Result';
Result:
Msg 174, Level 15, State 1, Line 1 The json_value function requires 2 argument(s).
Example 7 – Path Mode
In the earlier examples, when a function couldn’t handle the supplied path, it returned NULL
. This is because all of those examples were run in lax mode (the default mode).
If we’d run them in strict mode, we would’ve received an error instead. To explicitly specify the path mode, simply add it before the dollar sign (and leave a space between them).
Here’s an example of what happens when you provide an invalid path while in strict mode:
SELECT JSON_VALUE('{"Name": "Homer"}', 'strict $.Name') AS 'JSON_VALUE', JSON_QUERY('{"Name": "Homer"}', 'strict $.Name') AS 'JSON_QUERY';
Result:
Msg 13624, Level 16, State 2, Line 1 Object or array cannot be found in the specified JSON path.