{"id":2127,"date":"2015-12-15T00:00:00","date_gmt":"2015-12-14T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/json-support-in-sql-server-2016\/"},"modified":"2026-09-21T11:21:19","modified_gmt":"2026-09-21T11:21:19","slug":"json-support-in-sql-server-2016","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/json-support-in-sql-server-2016\/","title":{"rendered":"JSON support in SQL Server 2016"},"content":{"rendered":"\n<div class=\"article-content\">\n<p><strong>SQL Server has supported JSON since SQL Server 2016, and the functions have not changed since: FOR JSON turns a query result into JSON (AUTO for a shape derived from the query, PATH for one you control); OPENJSON shreds a JSON string into rows and columns; ISJSON tests whether a string is valid JSON; JSON_VALUE extracts a scalar and JSON_QUERY extracts an object or array; and JSON_MODIFY changes a value in place. <\/strong><\/p>\n<p><strong>JSON is stored in NVARCHAR columns (<a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/json-indexing-in-sql-server-2025-how-it-works-and-current-limitations\/\" target=\"_blank\" rel=\"noopener\">SQL Server 2025 adds a native json type<\/a>). This article works through each function with examples; for the design question &#8211; when to store JSON at all and how to index it &#8211; see <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/effective-strategies-for-storing-and-parsing-json-in-sql-server\/\" target=\"_blank\" rel=\"noopener\">Ed Pollack&#8217;s guide to storing and parsing JSON<\/a>.<\/strong><\/p>\n<p class=\"start\">SQL Server 2016 is finally adding support for JSON, a lightweight format for exchanging data between different source types, similar to how XML is used. JSON, short for JavaScript Object Notation, is based on a subset of the JavaScript programming language and is noted for being human readable and easy for computers to parse and generate.<\/p>\n<p>According to Microsoft, it is one of the most highly ranked requests on the Microsoft connect site and so for many, its inclusion in SQL Server is welcome news. That is, unless you were expecting the same sort of robust support we&#8217;ve seen with XML. SQL Server 2016 does not approach JSON with such vehemence, nor does it match what you&#8217;ll find in products such as PostgreSQL.<\/p>\n<p>SQL Server 2016 includes no JSON-specific data type and consequently none of the kinds of methods available to the <strong>XML<\/strong> data type. SQL Server 2016 continues to use the <strong>NVARCHAR<\/strong> type to store JSON data. However, it does provide several important T-SQL language elements that make working with JSON much easier than it has been in the past, so Microsoft is at least moving in the right direction, even if it still has some catching up to do.<\/p>\n<h2>Getting to know JSON<\/h2>\n<p>Although JSON is a bit more complex than what we&#8217;ll cover here, it can help to have a basic understanding of what makes up a JSON code snippet before starting in on the SQL Server support. At its most basic, a JSON snippet can contain objects, arrays, or both. An object is an unordered collection of one or more name\/value pairs (properties), enclosed in curly braces, as shown in the following example:<\/p>\n<pre class=\"listing\">\t{\"FirstName\":\"Terri\", \"Current\":true, \"Age\":42, \"Phone\":null}\n<\/pre>\n<p>For each property, the name component (<strong><code>FirstName<\/code><\/strong>, <strong><code>Current<\/code><\/strong>, <strong><code>Age<\/code><\/strong>, and <strong><code>Phone<\/code><\/strong>) is enclosed in double quotes and followed by a colon. The name component, sometimes referred to as the <em>key,<\/em> is always a string. The property&#8217;s value follows slightly different rules. If the value is a string, you should enclose it in double quotes. If it is a numeric value, Boolean value (<strong><code>true<\/code><\/strong> or <strong><code>false<\/code><\/strong>), or <strong><code>null<\/code><\/strong> value, do not enclose it in quotes.<\/p>\n<p>An array is simply an ordered collection of values, enclosed in square brackets, as in the following example:<\/p>\n<pre class=\"listing\">\t[\"Terri\", true, 42, null]\n<\/pre>\n<p>An array supports the same types of values as an object: string, number, <strong><code>true<\/code><\/strong>, <strong><code>false<\/code><\/strong>, or <strong><code>null<\/code><\/strong>. In addition, both objects and arrays can contain other objects and arrays as their values, providing a way to nest structures, as shown in the following example:<\/p>\n<pre class=\"listing\">{\n   \"Employees\":[\n      {\n         \"Name\":{\n            \"First\":\"Terri\",\n            \"Middle\":\"Lee\",\n            \"Last\":\"Duffy\"\n         },\n         \"PII\":{\n            \"DOB\":\"1971-08-01\",\n            \"NatID\":\"245797967\"\n         },\n         \"LoginID\":\"adventure-works\\\\terri0\"\n      },\n      {\n         \"Name\":{\n            \"First\":\"Roberto\",\n            \"Middle\":null,\n            \"Last\":\"Tamburello\"\n         },\n         \"PII\":{\n            \"DOB\":\"1974-11-12\",\n            \"NatID\":\"509647174\"\n         },\n         \"LoginID\":\"adventure-works\\\\roberto0\"\n      }\n   ]\n}<\/pre>\n<p>At the top level, we have a JSON object that includes a single property. The property&#8217;s name is <strong><code>Employees<\/code><\/strong>, and the value is an array, which contains two values. Each array value is a JSON object that includes the <strong><code>Name<\/code><\/strong>, <strong><code>PII<\/code><\/strong>, and <strong><code>LoginID<\/code><\/strong> properties. The <strong><code>Name<\/code><\/strong> and <strong><code>PII<\/code><\/strong> values are also JSON objects, which contain their own name\/value pairs.<\/p>\n<p>As we work through the examples in this article, you&#8217;ll get a better sense of how these various components work.<\/p>\n<h2>Formatting query results as JSON<\/h2>\n<p>One of the JSON-related features supported in SQL Server 2016 is the ability to return data in the JSON format, which we do by adding the <code><strong>FOR JSON<\/strong><\/code> clause to a <code><strong>SELECT<\/strong><\/code> statement. We&#8217;ll explore the basics of how to use a <code><strong>FOR JSON<\/strong><\/code> clause to return data in the JSON format, using either the <code><strong>AUTO<\/strong><\/code> argument or the <code>PATH<\/code> argument.<\/p>\n<p>First, however, we need some data on which to work. The following <code><strong>SELECT<\/strong><\/code> statement retrieves two rows from the <strong><code>vEmployee<\/code><\/strong> view in the <strong><code>AdventureWorks2016CTP3<\/code><\/strong> database:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">USE AdventureWorks2016CTP3;\ngo\n\nSELECT FirstName, MiddleName, LastName, \n  EmailAddress, PhoneNumber\nFROM HumanResources.vEmployee\nWHERE BusinessEntityID in (2, 3);<\/pre>\n<p>It returns the following results, although you might see some differences with the final product, since the data and examples are based on the CTP 3 release of SQL Server 2016:<\/p>\n<table>\n<thead>\n<tr>\n<td>FirstName<\/td>\n<td>MiddleName<\/td>\n<td>LastName<\/td>\n<td>EmailAddress<\/td>\n<td>PhoneNumber<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Terri<\/td>\n<td>Lee<\/td>\n<td>Duffy<\/td>\n<td>terri0@adventure-works.com<\/td>\n<td>819-555-0175<\/td>\n<\/tr>\n<tr>\n<td>Roberto<\/td>\n<td>NULL<\/td>\n<td>Tamburello<\/td>\n<td>roberto0@adventure-works.com<\/td>\n<td>212-555-0187<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>AUTO mode<\/h2>\n<p>To return these results as JSON, to support a specific application, we simply add the <code><strong>FOR JSON<\/strong><\/code> clause to the statement, as shown in the following example.<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT FirstName, MiddleName, LastName, \n  EmailAddress, PhoneNumber\nFROM HumanResources.vEmployee\nWHERE BusinessEntityID in (2, 3)\nFOR JSON AUTO;<\/pre>\n<p>Notice that the clause includes the <code><strong>AUTO<\/strong><\/code> argument, which indicates that the results should be returned in <code><strong>AUTO<\/strong><\/code> mode. When you specify this mode, the database engine automatically determines the <code><strong>JSON<\/strong><\/code> format, based on the order of the columns in the <code><strong>SELECT<\/strong><\/code> list and the tables in the <code><strong>FROM<\/strong><\/code> clause. In this case, the <code><strong>FOR JSON AUTO<\/strong><\/code> clause causes the <code><strong>SELECT<\/strong><\/code> statement to return the following results.<\/p>\n<pre class=\"listing\">\t[{\"FirstName\":\"Terri\",\"MiddleName\":\"Lee\",\"LastName\":\"Duffy\",\"EmailAddress\":\"terri0@adventure-works.com\",\"PhoneNumber\":\"819-555-0175\"},{\"FirstName\":\"Roberto\",\"LastName\":\"Tamburello\",\"EmailAddress\":\"roberto0@adventure-works.com\",\"PhoneNumber\":\"212-555-0187\"}]\n<\/pre>\n<p>From these results, you might be able to see that the JSON output includes an array that contains two values, with each value a JSON object. Not surprisingly, as the results become more involved, it becomes more difficult to read them. In such cases, you can use a local or online JSON formatter\/validator to turn the JSON snippet into something more readable. For example, I fed the previous results into the formatter at <a href=\"https:\/\/jsonformatter.curiousconcept.com\/\">https:\/\/jsonformatter.curiousconcept.com\/<\/a> and came up with the following JSON:<\/p>\n<pre class=\"listing\">[\n   {\n      \"FirstName\":\"Terri\",\n      \"MiddleName\":\"Lee\",\n      \"LastName\":\"Duffy\",\n      \"EmailAddress\":\"terri0@adventure-works.com\",\n      \"PhoneNumber\":\"819-555-0175\"\n   },\n   {\n      \"FirstName\":\"Roberto\",\n      \"LastName\":\"Tamburello\",\n      \"EmailAddress\":\"roberto0@adventure-works.com\",\n      \"PhoneNumber\":\"212-555-0187\"\n   }\n]<\/pre>\n<p>As you can see, it is now much easier to see our top-level array and the two object values it contains. Each object corresponds to a row returned by the <strong><code>SELECT<\/code><\/strong> statement. Going forward, I&#8217;ll show only the formatter-fed results so they&#8217;re more readable, but know that SQL Server returns the data as a single-line value, without all the whitespace and line breaks, as you saw above.<\/p>\n<p>Now that you&#8217;ve gotten a taste of the <code><strong>FOR JSON AUTO<\/strong><\/code> clause, let&#8217;s look at what happens when we join tables:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT e.BirthDate, e.NationalIDNumber, e.LoginID,\n  p.FirstName, p.MiddleName, p.LastName\nFROM HumanResources.Employee e INNER JOIN Person.Person p\n  ON e.BusinessEntityID = p.BusinessEntityID\nWHERE e.BusinessEntityID in (2, 3)\nFOR JSON AUTO;<\/pre>\n<p>As our <code><strong>SELECT<\/strong><\/code> statement becomes more complex, so too does the JSON output, as shown in the following results:<\/p>\n<pre class=\"listing\">[ \n   { \n      \"BirthDate\":\"1971-08-01\",\n      \"NationalIDNumber\":\"245797967\",\n      \"LoginID\":\"adventure-works\\\\terri0\",\n      \"p\":[\n         {\n            \"FirstName\":\"Terri\",\n            \"MiddleName\":\"Lee\",\n            \"LastName\":\"Duffy\"\n         }\n      ]\n   },\n   {\n      \"BirthDate\":\"1974-11-12\",\n      \"NationalIDNumber\":\"509647174\",\n      \"LoginID\":\"adventure-works\\\\roberto0\",\n      \"p\":[\n         {\n            \"FirstName\":\"Roberto\",\n            \"LastName\":\"Tamburello\"\n         }\n      ]\n   }\n]<\/pre>\n<p>The information from the <strong><code>Person<\/code><\/strong> table is now part of the <strong>p<\/strong> array, which itself is one of the values in the parent object. As you&#8217;ll recall, <code><strong>AUTO<\/strong><\/code> mode formats the results based on the order of the columns in the <code><strong>SELECT<\/strong><\/code> list and the tables in the <code><strong>FROM<\/strong><\/code> clause, so let&#8217;s mix up that column order:<\/p>\n<pre class=\"listing\">SELECT p.FirstName, p.MiddleName, p.LastName,\n  e.BirthDate, e.NationalIDNumber, e.LoginID\nFROM HumanResources.Employee e INNER JOIN Person.Person p\n  ON e.BusinessEntityID = p.BusinessEntityID\nWHERE e.BusinessEntityID in (2, 3)\nFOR JSON AUTO;<\/pre>\n<p>Now the <code><strong>SELECT<\/strong><\/code> statement will return the JSON with the data from the <strong><code>Employee<\/code><\/strong> table treated as the nested object:<\/p>\n<pre class=\"listing\">[\n   {\n      \"FirstName\":\"Terri\",\n      \"MiddleName\":\"Lee\",\n      \"LastName\":\"Duffy\",\n      \"e\":[\n         {\n            \"BirthDate\":\"1971-08-01\",\n            \"NationalIDNumber\":\"245797967\",\n            \"LoginID\":\"adventure-works\\\\terri0\"\n         }\n      ]\n   },\n   {\n      \"FirstName\":\"Roberto\",\n      \"LastName\":\"Tamburello\",\n      \"e\":[\n         {\n            \"BirthDate\":\"1974-11-12\",\n            \"NationalIDNumber\":\"509647174\",\n            \"LoginID\":\"adventure-works\\\\roberto0\"\n         }\n      ]\n   }\n]<\/pre>\n<p>As you can see, we have two <strong>e<\/strong> arrays, embedded in the outer objects. We can continue to play around with our <code><strong>SELECT<\/strong><\/code> statement to try to get closer to the JSON results we want, or we can instead use the <strong><code>PATH<\/code><\/strong> mode, which gives us full control over the format of the JSON output. For all but the most basic <code><strong>SELECT<\/strong><\/code> statements, you&#8217;ll likely want to use the <strong><code>PATH<\/code><\/strong> mode.<\/p>\n<h2>PATH mode<\/h2>\n<p>To use the <strong><code>PATH<\/code><\/strong> mode, we start be specifying <strong><code>PATH<\/code><\/strong> in the <code><strong>FOR JSON<\/strong><\/code> clause, rather than <code><strong>AUTO<\/strong><\/code>, as shown in the following example:<\/p>\n<pre class=\"listing\">SELECT p.FirstName, p.MiddleName, p.LastName,\n  e.BirthDate, e.NationalIDNumber, e.LoginID\nFROM HumanResources.Employee e INNER JOIN Person.Person p\n  ON e.BusinessEntityID = p.BusinessEntityID\nWHERE e.BusinessEntityID in (2, 3)\nFOR JSON PATH;<\/pre>\n<p>When we switch to the <strong><code>PATH<\/code><\/strong> mode, the database engine flattens out our results and returns the data as two object values within a single array:<\/p>\n<pre class=\"listing\">[\n   {\n      \"FirstName\":\"Terri\",\n      \"MiddleName\":\"Lee\",\n      \"LastName\":\"Duffy\",\n      \"BirthDate\":\"1971-08-01\",\n      \"NationalIDNumber\":\"245797967\",\n      \"LoginID\":\"adventure-works\\\\terri0\"\n   },\n   {\n      \"FirstName\":\"Roberto\",\n      \"LastName\":\"Tamburello\",\n      \"BirthDate\":\"1974-11-12\",\n      \"NationalIDNumber\":\"509647174\",\n      \"LoginID\":\"adventure-works\\\\roberto0\"\n   }\n]<\/pre>\n<p>Using the <strong><code>PATH<\/code><\/strong> mode in this way is fairly straightforward; however, this is <strong><code>PATH<\/code><\/strong> at its most basic. The mode lets us be far more specific. For example, we can control how the the database engine nests the JSON output by specifying column aliases that define the structure, as shown in the following <code><strong>SELECT<\/strong><\/code> clause:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT\n  p.FirstName AS [Name.First],\n  p.MiddleName AS [Name.Middle],\n  p.LastName AS [Name.Last],\n  e.BirthDate AS [PII.DOB], \n  e.NationalIDNumber AS [PII.NatID], \n  e.LoginID\nFROM HumanResources.Employee e INNER JOIN Person.Person p\n  ON e.BusinessEntityID = p.BusinessEntityID\nWHERE e.BusinessEntityID in (2, 3)\nFOR JSON PATH;<\/pre>\n<p>In this case, we are defining the <strong><code>Name<\/code><\/strong> object, which contains the <strong><code>First<\/code><\/strong>, <strong><code>Middle<\/code><\/strong>, and <strong><code>Last<\/code><\/strong> values; the <strong><code>PII<\/code><\/strong> object, which contains the <strong><code>DOB<\/code><\/strong> and <strong><code>NatID<\/code><\/strong> values; and the <strong><code>LoginID<\/code><\/strong> name\/value pair, as shown in the following results:<\/p>\n<pre class=\"listing\">[\n   {\n      \"Name\":{\n         \"First\":\"Terri\",\n         \"Middle\":\"Lee\",\n         \"Last\":\"Duffy\"\n      },\n      \"PII\":{\n         \"DOB\":\"1971-08-01\",\n         \"NatID\":\"245797967\"\n      },\n      \"LoginID\":\"adventure-works\\\\terri0\"\n   },\n   {\n      \"Name\":{\n         \"First\":\"Roberto\",\n         \"Last\":\"Tamburello\"\n      },\n      \"PII\":{\n         \"DOB\":\"1974-11-12\",\n         \"NatID\":\"509647174\"\n      },\n      \"LoginID\":\"adventure-works\\\\roberto0\"\n   }\n]<\/pre>\n<p>In some cases, you will want to add a single, top-level element to your JSON output to serve as a root. To do so, you must specify it as part of the <code><strong>FOR JSON<\/strong><\/code> clause, as shown in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT\n  p.FirstName AS [Name.First],\n  p.MiddleName AS [Name.Middle],\n  p.LastName AS [Name.Last],\n  e.BirthDate AS [PII.DOB], \n  e.NationalIDNumber AS [PII.NatID], \n  e.LoginID\nFROM HumanResources.Employee e INNER JOIN Person.Person p\n  ON e.BusinessEntityID = p.BusinessEntityID\nWHERE e.BusinessEntityID in (2, 3)\nFOR JSON PATH, ROOT('Employees');<\/pre>\n<p>To specify the root, we add the <strong><code>ROOT<\/code><\/strong> option to the <code><strong>FOR JSON<\/strong><\/code> clause and, in this case, name the root <strong><code>Employees<\/code><\/strong>, which gives us the following results:<\/p>\n<pre class=\"listing\">{\n   \"Employees\":[\n      {\n         \"Name\":{\n            \"First\":\"Terri\",\n            \"Middle\":\"Lee\",\n            \"Last\":\"Duffy\"\n         },\n         \"PII\":{\n            \"DOB\":\"1971-08-01\",\n            \"NatID\":\"245797967\"\n         },\n         \"LoginID\":\"adventure-works\\\\terri0\"\n      },\n      {\n         \"Name\":{\n            \"First\":\"Roberto\",\n            \"Last\":\"Tamburello\"\n         },\n         \"PII\":{\n            \"DOB\":\"1974-11-12\",\n            \"NatID\":\"509647174\"\n         },\n         \"LoginID\":\"adventure-works\\\\roberto0\"\n      }\n   ]\n}<\/pre>\n<p>If you compare these results to those from the previous example, you will see that the outer element has been changed from an array to an object that contains only the <strong><code>Employees<\/code><\/strong> property. The <strong><code>Employees<\/code><\/strong> value is now the array that was the outer element in the previous example.<\/p>\n<p>You might have also noticed that the second employee, Roberto, includes no middle name. That is because the <strong>MiddleName<\/strong> column in the source table is null. By default, the database engine does not include a JSON element whose value is null. However, you can override this behavior by adding the <strong>INCLUDE_NULL_VALUES<\/strong> option to the <code><strong>FOR JSON<\/strong><\/code> clause, as shown in the following <code><strong>SELECT<\/strong><\/code> statement:<\/p>\n<p>SELECT<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT\n  p.FirstName AS [Name.First],\n  p.MiddleName AS [Name.Middle],\n  p.LastName AS [Name.Last],\n  e.BirthDate AS [PII.DOB], \n  e.NationalIDNumber AS [PII.NatID], \n  e.LoginID\nFROM HumanResources.Employee e INNER JOIN Person.Person p\n  ON e.BusinessEntityID = p.BusinessEntityID\nWHERE e.BusinessEntityID in (2, 3)\nFOR JSON PATH, ROOT('Employees'), INCLUDE_NULL_VALUES;<\/pre>\n<p>Now the results will show that Roberto&#8217;s middle name is null by assigning the <strong><code>null<\/code><\/strong> value to the <strong>Middle<\/strong> property:<\/p>\n<pre class=\"listing\">{\n   \"Employees\":[\n      {\n         \"Name\":{\n            \"First\":\"Terri\",\n            \"Middle\":\"Lee\",\n            \"Last\":\"Duffy\"\n         },\n         \"PII\":{\n            \"DOB\":\"1971-08-01\",\n            \"NatID\":\"245797967\"\n         },\n         \"LoginID\":\"adventure-works\\\\terri0\"\n      },\n      {\n         \"Name\":{\n            \"First\":\"Roberto\",\n            \"Middle\":null,\n            \"Last\":\"Tamburello\"\n         },\n         \"PII\":{\n            \"DOB\":\"1974-11-12\",\n            \"NatID\":\"509647174\"\n         },\n         \"LoginID\":\"adventure-works\\\\roberto0\"\n      }\n   ]\n}<\/pre>\n<p>There are, of course, other considerations to take into account when using this clause, so be sure to refer to SQL Server 2016 documentation. In the meantime, let&#8217;s look at how to convert a JSON snippet to traditional rowset data.<\/p>\n<h2>Converting JSON to rowset data using the OPENJSON function<\/h2>\n<p>To return a JSON snippet as rowset data, we use the <strong><code>OPENJSON<\/code><\/strong> rowset function to convert the data to a relational format. The function returns three values:<\/p>\n<ul>\n<li><strong>key:<\/strong> Property name within the object or index of the element within the array.<\/li>\n<li><strong><code>value<\/code><\/strong><strong>:<\/strong> Property value within the object or value of the array element specified by the index.<\/li>\n<li><strong>type:<\/strong> Value&#8217;s data type, represented numerically, as described in the following table:<\/li>\n<\/ul>\n<table>\n<thead>\n<tr>\n<td>Numeric value<\/td>\n<td>Data type<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>0<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>string<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>int<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>true or false<\/td>\n<\/tr>\n<tr>\n<td>4<\/td>\n<td>array<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>object<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To test how the the <strong><code>OPENJSON<\/code><\/strong> function works, let&#8217;s assign a JSON snippet to a variable and then use the function to call the variable, as shown in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">DECLARE @json NVARCHAR(MAX) = N'\n{\n  \"FirstName\":null,\n  \"LastName\":\"Duffy\",\n  \"NatID\":245797967,\n  \"Current\":false,\n  \"Skills\":[\"Dev\",\"QA\",\"PM\"],\n  \"Region\":{\"Country\":\"Canada\",\"Territory\":\"North America\"}\n}';\n\nSELECT * FROM OPENJSON(@json);<\/pre>\n<p>The JSON snippet contains a single object that includes a property for each data type. The <code><strong>SELECT<\/strong><\/code> statement uses the <strong><code>OPENJSON<\/code><\/strong> rowset function within the <code><strong>FROM<\/strong><\/code> clause to retrieve the JSON data as a rowset, as shown in the following results:<\/p>\n<table>\n<thead>\n<tr>\n<td>key<\/td>\n<td>value<\/td>\n<td>type<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>FirstName<\/td>\n<td>NULL<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>LastName<\/td>\n<td>Duffy<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>NatID<\/td>\n<td>245797967<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>Current<\/td>\n<td>false<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<td>Skills<\/td>\n<td>[&#8220;Dev&#8221;,&#8221;QA&#8221;,&#8221;PM&#8221;]<\/td>\n<td>4<\/td>\n<\/tr>\n<tr>\n<td>Region<\/td>\n<td>{&#8220;Country&#8221;:&#8221;Canada&#8221;,&#8221;Territory&#8221;:&#8221;North America&#8221;}<\/td>\n<td>5<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Notice that the <strong><code>type<\/code><\/strong> column in the results identifies the data type for each value. As expected, the column shows the <strong><code>Skills<\/code><\/strong> value an array, with all of the array&#8217;s elements included in the results for that row. The same goes for the <strong><code>Region<\/code><\/strong> value, which is an object. The row includes all the properties within that object.<\/p>\n<p>In some cases, you will want to return only the <strong><code>key<\/code><\/strong> and <strong><code>value<\/code><\/strong> columns, so you will need to specify those columns in your <code><strong>SELECT<\/strong><\/code> list:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT [key], value\nFROM OPENJSON(@json);<\/pre>\n<p>Notice that you must delimit the <strong><code>key<\/code><\/strong> column because Microsoft chose to return a column name that is also a T-SQL reserved keyword. As the following table shows, the results include only those two columns:<\/p>\n<table>\n<thead>\n<tr>\n<td>key<\/td>\n<td>value<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>FirstName<\/td>\n<td>NULL<\/td>\n<\/tr>\n<tr>\n<td>LastName<\/td>\n<td>Duffy<\/td>\n<\/tr>\n<tr>\n<td>NatID<\/td>\n<td>245797967<\/td>\n<\/tr>\n<tr>\n<td>Current<\/td>\n<td>false<\/td>\n<\/tr>\n<tr>\n<td>Skills<\/td>\n<td>[&#8220;Dev&#8221;,&#8221;QA&#8221;,&#8221;PM&#8221;]<\/td>\n<\/tr>\n<tr>\n<td>Region<\/td>\n<td>{&#8220;Country&#8221;:&#8221;Canada&#8221;,&#8221;Territory&#8221;:&#8221;North America&#8221;}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Now let&#8217;s move on to a more complex JSON snippet, which we&#8217;ll use for the remaining examples in this article:<\/p>\n<pre class=\"listing\">{\n   \"Employees\":[\n      {\n         \"Name\":{\n            \"First\":\"Terri\",\n            \"Middle\":\"Lee\",\n            \"Last\":\"Duffy\"\n         },\n         \"PII\":{\n            \"DOB\":\"1971-08-01\",\n            \"NatID\":\"245797967\"\n         },\n         \"LoginID\":\"adventure-works\\\\terri0\"\n      },\n      {\n         \"Name\":{\n            \"First\":\"Roberto\",\n            \"Middle\":null,\n            \"Last\":\"Tamburello\"\n         },\n         \"PII\":{\n            \"DOB\":\"1974-11-12\",\n            \"NatID\":\"509647174\"\n         },\n         \"LoginID\":\"adventure-works\\\\roberto0\"\n      }\n   ]\n}<\/pre>\n<p>The JSON shown here comes from the output generated from the last example in the preceding section. As you&#8217;ll recall, the database engine actually outputs the JSON in a format much less readable than what is shown here, but it can be easier to work with when assigning the JSON to a variable. So that&#8217;s the approach we&#8217;ll take for the remaining examples:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">DECLARE @json NVARCHAR(MAX) = N'{\"Employees\":[{\"Name\":{\"First\":\"Terri\",\"Middle\":\"Lee\",\"Last\":\"Duffy\"},\"PII\":{\"DOB\":\"1971-08-01\",\"NatID\":\"245797967\"},\"LoginID\":\"adventure-works\\\\terri0\"},{\"Name\":{\"First\":\"Roberto\",\"Middle\":null,\"Last\":\"Tamburello\"},\"PII\":{\"DOB\":\"1974-11-12\",\"NatID\":\"509647174\"},\"LoginID\":\"adventure-works\\\\roberto0\"}]}';\n<\/pre>\n<p>If you plan to try out the next batch of examples, you can use this variable definition for each one, which avoids all the whitespace you get when you run the results through a parser. Now let&#8217;s use the <strong><code>OPENJSON<\/code><\/strong> function to convert the JSON in the variable:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT [key], value\nFROM OPENJSON(@json);<\/pre>\n<p>The example uses <strong><code>OPENJSON<\/code><\/strong> at its most basic, with no other parameters defined. As a result, the <code><strong>SELECT<\/strong><\/code> statement returns only a single row for the <strong><code>Employees<\/code><\/strong> array, as shown in the following table:<\/p>\n<table>\n<thead>\n<tr>\n<td>key<\/td>\n<td>value<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Employees<\/td>\n<td>[{&#8220;Name&#8221;:{&#8220;First&#8221;:&#8221;Terri&#8221;,&#8221;Middle&#8221;:&#8221;Lee&#8221;,&#8221;Last&#8221;:&#8221;Duffy&#8221;},&#8221;PII&#8221;:{&#8220;DOB&#8221;:&#8221;1971-08-01&#8243;,&#8221;NatID&#8221;:&#8221;245797967&#8243;},&#8221;LoginID&#8221;:&#8221;adventure-works\\\\terri0&#8243;},{&#8220;Name&#8221;:{&#8220;First&#8221;:&#8221;Roberto&#8221;,&#8221;Middle&#8221;:null,&#8221;Last&#8221;:&#8221;Tamburello&#8221;},&#8221;PII&#8221;:{&#8220;DOB&#8221;:&#8221;1974-11-12&#8243;,&#8221;NatID&#8221;:&#8221;509647174&#8243;},&#8221;LoginID&#8221;:&#8221;adventure-works\\\\roberto0&#8243;}]<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To better control our results, we need to pass a second argument into the <strong><code>OPENJSON<\/code><\/strong> function. The argument is a JSON path that instructs the database engine on how to parse the data. For example, the following path instructs the database engine to return data based on the <strong><code>Employees<\/code><\/strong> property:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT [key], value\nFROM OPENJSON(@json, '$.Employees');<\/pre>\n<p>When you specify a JSON path, you start with a dollar sign (<strong>$<\/strong>) to represent the item as it exists in its current context. You then specify one or more elements as they appear hierarchically in the JSON snippet, using periods to separate the elements. In this case, the path specifies only the root element, <strong><code>Employees<\/code><\/strong>, giving us the results shown in the following table:<\/p>\n<table>\n<thead>\n<tr>\n<td>key<\/td>\n<td>value<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>0<\/td>\n<td>{&#8220;Name&#8221;:{&#8220;First&#8221;:&#8221;Terri&#8221;,&#8221;Middle&#8221;:&#8221;Lee&#8221;,&#8221;Last&#8221;:&#8221;Duffy&#8221;},&#8221;PII&#8221;:{&#8220;DOB&#8221;:&#8221;1971-08-01&#8243;,&#8221;NatID&#8221;:&#8221;245797967&#8243;},&#8221;LoginID&#8221;:&#8221;adventure-works\\\\terri0&#8243;}<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>{&#8220;Name&#8221;:{&#8220;First&#8221;:&#8221;Roberto&#8221;,&#8221;Middle&#8221;:null,&#8221;Last&#8221;:&#8221;Tamburello&#8221;},&#8221;PII&#8221;:{&#8220;DOB&#8221;:&#8221;1974-11-12&#8243;,&#8221;NatID&#8221;:&#8221;509647174&#8243;},&#8221;LoginID&#8221;:&#8221;adventure-works\\\\roberto0&#8243;}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This time, we get a row for each element in the <strong><code>Employees<\/code><\/strong> array. If we want to break the results down even further, we must work down the hierarchy. For example, to reference an element within the <strong><code>Employees<\/code><\/strong> array, we must specify the element&#8217;s index, as it exists within the array. An array&#8217;s index is zero-based, which means the index count starts with 0, so if we want to retrieve the first element in the <strong><code>Employees<\/code><\/strong> array, we must specify <strong>0<\/strong> after the root name, within square brackets, as shown in the following statement:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT [key], value\nFROM OPENJSON(@json, '$.Employees[0]');<\/pre>\n<p>The first element in the <strong><code>Employees<\/code><\/strong> array is a JSON object that contains three properties, so that is what the <code><strong>SELECT<\/strong><\/code> statement returns, as shown in the following results:<\/p>\n<table>\n<thead>\n<tr>\n<td>key<\/td>\n<td>value<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Name<\/td>\n<td>{&#8220;First&#8221;:&#8221;Terri&#8221;,&#8221;Middle&#8221;:&#8221;Lee&#8221;,&#8221;Last&#8221;:&#8221;Duffy&#8221;}<\/td>\n<\/tr>\n<tr>\n<td>PII<\/td>\n<td>{&#8220;DOB&#8221;:&#8221;1971-08-01&#8243;,&#8221;NatID&#8221;:&#8221;245797967&#8243;}<\/td>\n<\/tr>\n<tr>\n<td>LoginID<\/td>\n<td>adventure-works\\terri0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Because the first two values are objects, the entire contents of those objects are returned. However, we can instead return only one of those objects by specify the object name:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT [key], value\nFROM OPENJSON(@json, '$.Employees[0].Name');<\/pre>\n<p>Now the <code><strong>SELECT<\/strong><\/code> statement returns only the three properties within the <strong><code>Name<\/code><\/strong> object:<\/p>\n<table>\n<thead>\n<tr>\n<td>key<\/td>\n<td>value<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>First<\/td>\n<td>Terri<\/td>\n<\/tr>\n<tr>\n<td>Middle<\/td>\n<td>Lee<\/td>\n<\/tr>\n<tr>\n<td>Last<\/td>\n<td>Duffy<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The <strong><code>OPENJSON<\/code><\/strong> examples we&#8217;ve looked at so far have used the default schema when returning the data as a rowset, but there are limits to how well we can control the results. Fortunately, the <strong><code>OPENJSON<\/code><\/strong> function also lets us add a <strong><code>WITH<\/code><\/strong> clause to our <code><strong>SELECT<\/strong><\/code> statement in order to define an explicit schema. In the following example, the schema flattens out our data so we can easily see the details for each employee:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT *\nFROM OPENJSON(@json, '$.Employees')\nWITH([Name.First] NVARCHAR(25), [Name.Middle] NVARCHAR(25), \n  [Name.Last] NVARCHAR(25), [PII.DOB] DATE, [PII.NatID] INT);<\/pre>\n<p>The <strong><code>WITH<\/code><\/strong> clause specifies each column, using names that link to the original JSON. For example, the <strong><code>Name.First<\/code><\/strong> column returns the employee&#8217;s first name. The column name is based on the <strong><code>First<\/code><\/strong> property within the <strong><code>Name<\/code><\/strong> object. For each column, we also provide a T-SQL data type. The <code><strong>SELECT<\/strong><\/code> statement now returns the results shown in the following table:<\/p>\n<table>\n<thead>\n<tr>\n<td>Name.First<\/td>\n<td>Name.Middle<\/td>\n<td>Name.Last<\/td>\n<td>PII.DOB<\/td>\n<td>PII.NatID<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Terri<\/td>\n<td>Lee<\/td>\n<td>Duffy<\/td>\n<td>1971-08-01<\/td>\n<td>245797967<\/td>\n<\/tr>\n<tr>\n<td>Roberto<\/td>\n<td>NULL<\/td>\n<td>Tamburello<\/td>\n<td>1974-11-12<\/td>\n<td>509647174<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If we want to define more readable column names, we can instead create column definitions that each includes the new name, followed the data type, and then a path reference, as shown in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT *\nFROM OPENJSON(@json, '$.Employees')\nWITH(FirstName NVARCHAR(25) '$.Name.First', \n  MiddleName NVARCHAR(25) '$.Name.Middle', \n  LastName NVARCHAR(25) '$.Name.Last', \n  BirthDate DATE '$.PII.DOB', \n  NationalID INT '$.PII.NatID');<\/pre>\n<p>Notice that, for the path, we do not need to reference the <strong><code>Employees<\/code><\/strong> array itself. That&#8217;s taken care of in the <strong><code>OPENJSON<\/code><\/strong> function. But we still need to specify the dollar sign to show the current context. We then follow with the <strong><code>Name<\/code><\/strong> or <strong><code>PII<\/code><\/strong> object name and then the property name. The <code><strong>SELECT<\/strong><\/code> statement now returns the results shown in the following table:<\/p>\n<table>\n<thead>\n<tr>\n<td>FirstName<\/td>\n<td>MiddleName<\/td>\n<td>LastName<\/td>\n<td>BirthDate<\/td>\n<td>NationalID<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Terri<\/td>\n<td>Lee<\/td>\n<td>Duffy<\/td>\n<td>1971-08-01<\/td>\n<td>245797967<\/td>\n<\/tr>\n<tr>\n<td>Roberto<\/td>\n<td>NULL<\/td>\n<td>Tamburello<\/td>\n<td>1974-11-12<\/td>\n<td>509647174<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The preceding examples should give you at least a basic idea of how to turn a JSON snippet into rowset data. Again, refer to SQL Server 2016 documentation to get more specifics about how to use the <strong><code>OPENJSON<\/code><\/strong> function.<\/p>\n<h2>More JSON functions in SQL Server 2016<\/h2>\n<p>In addition to <strong><code>OPENJSON<\/code><\/strong>, SQL Server 2016 includes several other functions for working with JSON data. We&#8217;ll review how to use the <strong><code>ISJSON<\/code><\/strong>, <strong><code>JSON_value<\/code><\/strong> functions, and <strong><code>JSON_ QUERY<\/code><\/strong> functions.<\/p>\n<h3>ISJSON<\/h3>\n<p>The <strong><code>ISJSON<\/code><\/strong> function lets you test whether a text string is correctly formatted JSON. This is a particularly important function, considering that SQL Server 2016 doesn&#8217;t support a JSON data type. At least this way, you have some way to validate your data.<\/p>\n<p>The <strong><code>ISJSON<\/code><\/strong> function returns <strong><code>1<\/code><\/strong> if a string is valid JSON, otherwise returns <strong><code>0<\/code><\/strong>. The only exception to this is if the string is null, in which case the function returns null. The following <code><strong>SELECT<\/strong><\/code> statement tests our ubiquitous <strong><code>@json<\/code><\/strong> variable to verify whether it is valid:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT CASE \n  WHEN ISJSON(@json) &gt; 0 \n    THEN 'The variable value is JSON.' \n    ELSE 'The variable value is not JSON.' \n  END;<\/pre>\n<p>As we hoped, the <code><strong>SELECT<\/strong><\/code> statement returns the following results:<\/p>\n<pre class=\"listing\">The variable value is JSON.<\/pre>\n<p>Now let&#8217;s pass in text that is not valid JSON by tagging on the <strong>Age<\/strong> element without a value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">DECLARE @json2 NVARCHAR(MAX) = N'\n{\"First\":\"Terri\",\"Middle\":\"Lee\",\"Last\":\"Duffy\",\"Age\"}';\n\nSELECT CASE \n  WHEN ISJSON(@json2) &gt; 0 \n    THEN 'The variable value is JSON.' \n    ELSE 'The variable value is not JSON.' \n  END;<\/pre>\n<p>As expected, we receive the second message:<\/p>\n<pre class=\"listing\">The variable value is not JSON.<\/pre>\n<h3>JSON_VALUE<\/h3>\n<p>Another handy JSON-related function in SQL Server 2016 is <strong><code>JSON_VALUE<\/code><\/strong>, which lets us extract a scalar value from a JSON snippet, as shown in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT JSON_VALUE(@json, '$.Employees[0].Name.First');<\/pre>\n<p>The <strong><code>JSON_VALUE<\/code><\/strong> function takes two arguments. The first is the JSON itself, and the second is a path that defines which element&#8217;s value we want to retrieve. In this case, the path specifies the <strong><code>First<\/code><\/strong> property in the <strong><code>Name<\/code><\/strong> object, which is part of the first element in the <strong><code>Employees<\/code><\/strong> array. As we would expect, the <code><strong>SELECT<\/strong><\/code> statement returns the value <strong><code>Terri<\/code><\/strong>.<\/p>\n<p>We can just as easily return the <strong><code>NatID<\/code><\/strong> value for the second employee:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT JSON_VALUE(@json, '$.Employees[1].PII.NatID');<\/pre>\n<p>Now the <code><strong>SELECT<\/strong><\/code> statement returns <strong><code>509647174<\/code><\/strong>. Suppose, however, that we try to retrieve something other than a scalar value. For example, the following path specifies only the <strong>PII<\/strong> object for the second employee:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT JSON_VALUE(@json, '$.Employees[1].PII');<\/pre>\n<p>This time, the <code><strong>SELECT<\/strong><\/code> statement returns a null value. By default, the database engine returns a null value if the path does not exist or is not applicable to the current situation. In this example, we&#8217;ve specified an element that cannot return a scalar value, so the database engine returns the null value.<\/p>\n<p>When specifying a path in a JSON-related expression, you can control the results by preceding the path with the <strong>lax<\/strong> or <strong>strict<\/strong> option. The <strong>lax<\/strong> option is the default and is implied if not specified, which means that the database engine returns a null value if a problem arises. For example, the following path explicitly includes the <strong>lax<\/strong> option:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT JSON_VALUE(@json, 'lax $.Employees[1].PII');<\/pre>\n<p>Once again, out statement returns a null value because we&#8217;re specifying an element that cannot return a scalar value. We can instead specify the <strong>strict<\/strong> option, in which case, the database engine will raise an error if a problem occurs:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT JSON_VALUE(@json, 'strict $.Employees[1].PII');<\/pre>\n<p>This time we receive very different results:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">Property cannot be found in specified path.<\/pre>\n<h3>JSON_QUERY<\/h3>\n<p>Another useful JSON-related tool is the <strong><code>JSON_QUERY<\/code><\/strong> function, which can extract an object or array from a JSON snippet. For example, the following <code><strong>SELECT<\/strong><\/code> statement retrieves the <strong><code>PII<\/code><\/strong> object for the second employee:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT JSON_QUERY(@json, 'strict $.Employees[1].PII');<\/pre>\n<p>Like the <strong><code>JSON_value<\/code><\/strong> function, the <strong><code>JSON_QUERY<\/code><\/strong> function takes two arguments: the JSON source and a path indicating what data to extract. The <code><strong>SELECT<\/strong><\/code> statement returns the following results:<\/p>\n<pre class=\"listing\">{\"DOB\":\"1974-11-12\",\"NatID\":\"509647174\"}<\/pre>\n<p>If we want to return the <strong><code>Employees<\/code><\/strong> array, we simply specify <strong><code>$.Employees<\/code><\/strong> as our path:<\/p>\n<pre class=\"lang:tsql theme:ssms2012\">SELECT JSON_QUERY(@json, 'strict $.Employees');<\/pre>\n<p>Now the <code><strong>SELECT<\/strong><\/code> statement returns just about everything in our JSON snippet:<\/p>\n<pre class=\"listing\">[{\"Name\":{\"First\":\"Terri\",\"Middle\":\"Lee\",\"Last\":\"Duffy\"},\"PII\":{\"DOB\":\"1971-08-01\",\"NatID\":\"245797967\"},\"LoginID\":\"adventure-works\\\\terri0\"},{\"Name\":{\"First\":\"Roberto\",\"Middle\":null,\"Last\":\"Tamburello\"},\"PII\":{\"DOB\":\"1974-11-12\",\"NatID\":\"509647174\"},\"LoginID\":\"adventure-works\\\\roberto0\"}]<\/pre>\n<h2>Summary: JSON and SQL Server 2016<\/h2>\n<p>This article should give you what you need to start working with JSON data in SQL Server. As you can see, however, JSON support is nowhere nearly as robust as XML support. And if you&#8217;re working with other database management systems, you&#8217;ll quickly discover that the JSON features in SQL Server 2016 have some catching up to do before they can match what&#8217;s been implemented in other products.<\/p>\n<p>Even so, what SQL Server 2016 provides is better than nothing, and the JSON support is solid and could prove more than adequate much of the time. In fact, for some organizations, the JSON features already implemented in SQL Server 2016 will be enough to meet their needs. Best of all, the JSON-related functionality is straightforward and easy-to-use, so you should be able to incorporate it into your workflow with relatively little pain.<\/p>\n<\/div>\n\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. How should I store and query JSON in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Store JSON text in an NVARCHAR(MAX) column (or the native json type in SQL Server 2025), keep it for genuinely semi-structured data rather than as a substitute for columns, and query it with JSON_VALUE for scalars, JSON_QUERY for fragments and OPENJSON to turn it into rows you can join. To index a value inside the JSON, create a computed column with JSON_VALUE and index that. For the full design discussion, see Effective Strategies for Storing and Parsing JSON in SQL Server.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. What is the difference between FOR JSON AUTO and FOR JSON PATH?<\/h3>\n            <div class=\"faq-answer\">\n                <p>AUTO builds the JSON structure from the query &#8211; nesting follows the joins and column names become keys &#8211; with little control. PATH lets you define the structure with dot-separated column aliases (for example &#8216;address.city&#8217;), which is what you want when the JSON must match an application&#8217;s schema.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. What is the difference between JSON_VALUE and JSON_QUERY?<\/h3>\n            <div class=\"faq-answer\">\n                <p>JSON_VALUE returns a scalar &#8211; a string, number or boolean &#8211; at a path. JSON_QUERY returns an object or array as JSON text. Using JSON_VALUE on an object returns NULL, which is the most common cause of unexpected NULLs when reading JSON.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">4. How do you convert JSON to rows in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <p>With OPENJSON: OPENJSON(@json) returns key\/value\/type rows, and OPENJSON(@json) WITH (col1 type &#8216;path&#8217;, &#8230;) returns a typed rowset you can join, insert or aggregate. The article covers both forms.<\/p>\n            <\/div>\n            <\/section>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>How SQL Server handles JSON: format results with FOR JSON AUTO and PATH, shred JSON into rows with OPENJSON, and read values with JSON_VALUE and JSON_QUERY.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":true,"footnotes":""},"categories":[143525],"tags":[4880,4149,4150,4151,6089,4217],"coauthors":[6779],"class_list":["post-2127","post","type-post","status-publish","format-standard","hentry","category-learn","tag-json","tag-learn-sql-server","tag-sql","tag-sql-server","tag-sql-server-2016","tag-xml"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=2127"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2127\/revisions"}],"predecessor-version":[{"id":113152,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2127\/revisions\/113152"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=2127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=2127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=2127"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=2127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}