天天看点

SQL Server 2016中的本机JSON支持

With the introduction of SQL Server 2016, Microsoft introduced many new features which had taken SQL Server another step forward and they made sure that it stands in front among many major Relational Database Systems.

随着SQL Server 2016的推出,Microsoft引入了许多新功能,这些新功能使SQL Server向前迈进了一步,并确保SQL Server在许多主要的关系数据库系统中处于领先地位。

One such feature which has been lacking but desperately required was the native support towards JSON.

一直缺少但迫切需要的此类功能之一就是对JSON的本机支持。

Before SQL Server 2016, there were many other databases which already had the support for JSON.

在SQL Server 2016之前,还有许多其他数据库已经支持JSON。

PostgreSQL, Oracle, and MongoDB are few to be mentioned among many other databases which support JSON natively.

在许多其他本机支持JSON的数据库中,很少提及PostgreSQL,Oracle和MongoDB。

什么是JSON? (What’s JSON?)

JSON is an acronym which stands for JavaScript Object Notation. It has been a very popular among web developers due to many of its features. Being lightweight and easily readable (since it’s text based) had made JSON extremely popular in web development.

JSON是首字母缩写,代表JavaScript对象表示法。 由于其许多功能,它在Web开发人员中非常受欢迎。 轻量级且易于阅读(因为它是基于文本的)使JSON在Web开发中非常流行。

What are the functions introduced to support JSON in SQL 2016 ?

引入了哪些功能来支持SQL 2016中的JSON?

A few functions have been introduced with SQL 2016 in order to support JSON natively in SQL Server 2016. These functions are:

SQL 2016引入了一些功能,以便在SQL Server 2016中原生支持JSON。这些功能是:

  • ISJSON ISJSON
  • JSON_VALUE JSON_VALUE
  • JSON_QUERY JSON_QUERY
  • JSON_MODIFY JSON_MODIFY
  • OPENJSON OPENJSON
  • FOR JSON 对于JSON

**Note: Unlike XML, in SQL Server there’s no specific data type to accommodate JSON. Hence we need to use NVARCHAR.

**注意:与XML不同,SQL Server中没有特定的数据类型来容纳JSON。 因此,我们需要使用NVARCHAR。

We will go bit deep into the functions individually.

我们将逐一深入介绍这些功能。

First we will see how we should declare a variable and assign a JSON string to it.

首先,我们将看到如何声明变量并为其分配JSON字符串。

 
DECLARE @vJson AS NVARCHAR(4000) = N'{"EmployeeInfo": {
			"FirstName": "John",
			"LastName": "Doe",
			"Dob": "12-Jan-1970",
			"AnnualSalary": 85000
		}}’
 
           

It’s simple as assigning a string value to a NVARCHAR type variable.

将字符串值分配给NVARCHAR类型变量很简单。

Now we will look more closely into each of the functions which mentioned previously. We will see what it does and how we can use them in our T-SQL statements.

现在,我们将更仔细地研究前面提到的每个功能。 我们将在T-SQL语句中看到它的作用以及如何使用它们。

ISJSON函数 (ISJSON Function)

This is the simplest of the functions for JSON support in SQL Server. It takes one string argument as the input, validate it and returns a BIT; 1 if the provided JSON is a valid one or returns 0 if it doesn’t.

这是SQL Server中最简单的JSON支持功能。 它以一个字符串参数作为输入,对其进行验证并返回BIT; 如果提供的JSON有效,则为1;否则,则返回0。

If the provided input argument is NULL then the return value will also be NULL.

如果提供的输入参数为NULL,则返回值也将为NULL。

Syntax: 句法:
 
ISJSON(@input)
 
           
Example: 例:
 
DECLARE @vJson AS NVARCHAR(4000) = N'{"EmployeeInfo": {
			"FirstName": "John",
			"LastName": "Doe",
			"Dob": "12-Jan-1970",
			"AnnualSalary": 85000
		}
	}’
 
 
IF (ISJSON(@vJson))
	PRINT ‘Valid JSON’
ELSE
	PRINT ‘Invalid JSON’
 
           

When this statement is executed you can see that it returns 1, since the provided JSON string is a valid one.

执行此语句后,您会看到它返回1,因为提供的JSON字符串是有效的。

However there’s a concern when it comes to validate using ISJSON. That is ISJSON will not validate whether the key is unique or not.

但是,在使用ISJSON进行验证时存在一个问题。 即ISJSON将不会验证密钥是否唯一。

Example: 例:

We will use the same JSON string but this time we will duplicate the key ‘FirstName’.

我们将使用相同的JSON字符串,但是这次我们将复制键“ FirstName”。

 
DECLARE @vJson AS NVARCHAR(4000) = N'{"EmployeeInfo": {
			"FirstName": "John",
			"FirstName": "John",
			"LastName": "Doe",
			"Dob": "12-Jan-1970",
			"AnnualSalary": 85000
		}
	}’
 
 
IF (ISJSON(@vJson))
	PRINT ‘Valid JSON’
ELSE
	PRINT ‘Invalid JSON’ 
 
           

If you execute the above code, you will still get the return value as 1, even the JSON string is containing a duplicate key. Most of the JSON validators will find these kind of JSON strings as invalid. (E.g: http://jsonlint.com/)

如果执行上述代码,即使JSON字符串包含重复键,您仍将获得返回值1。 大多数JSON验证程序都会将这些JSON字符串视为无效。 (例如: http : //jsonlint.com/ )

Further reading can be done on ISJSON (Transact-SQL)

可以在ISJSON(Transact-SQL)上进行进一步的阅读

JSON_VALUE函数 (JSON_VALUE Function)

JSON_VALUE will return a scalar value from a JSON string for a requested key. To illustrate this we will use a different JSON string which contains an array.

JSON_VALUE将从JSON字符串中为请求的键返回标量值。 为了说明这一点,我们将使用另一个包含数组的JSON字符串。

 
DECLARE @vJson AS NVARCHAR(4000) = N'{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		]}'
 
           

Using the above details will fetch the employee’s first name and the name of employee’s son. We can do this using the below shown syntax.

使用以上详细信息将获取员工的名字和员工儿子的名字。 我们可以使用下面显示的语法来做到这一点。

 
SELECT JSON_VALUE(@vJson,'$.EmployeeInfo.FirstName') AS EmployeeName
SELECT JSON_VALUE(@vJson,'$.Dependants[1].DepName') AS EmployeeSonName 
 
           

This will return ‘John’ and ‘James’ respectively. There are few things to be noted here.

这将分别返回“ John”和“ James”。 这里有几件事需要注意。

  • The array index starts with zero. Hence we need to say we want the 1st index in order to get son’s name which is the second element. If the index is out of the range it will return a NULL

    数组索引从零开始。 因此,我们需要说我们想要第一个索引,以获得第二个元素的儿子的名字。 如果索引超出范围,它将返回NULL

  • The JSON path is case sensitive. Therefore it should match exactly with what you have on the JSON string. If the path is not found it will return NULL.

    JSON路径区分大小写。 因此,它应该与JSON字符串上的内容完全匹配。 如果找不到该路径,它将返回NULL。

As an example both these will return NULL.

作为示例,这两个都将返回NULL。

 
SELECT JSON_VALUE(@vJson,'$.EmployeeInfo.firstName') AS EmployeeName
SELECT JSON_VALUE(@vJson,'$.Dependants[0].DepName') AS EmployeeSonName  
 
           

But at times we require knowing why it is returning NULL. It could be a possibility where the underlying value for that JSON path is having a NULL value. So in order to distinguish between these, we need to include ‘strict’ keyword before the JSON path.

但是有时我们需要知道为什么它返回NULL。 如果该JSON路径的基础值具有NULL值,则可能会出现这种情况。 因此,为了区分这些,我们需要在JSON路径之前包含'strict'关键字。

 
SELECT JSON_VALUE(@vJson,'strict $.EmployeeInfo.firstName') AS EmployeeName
 
           

Executing this will result with the following error message:

执行此操作将导致以下错误消息:

SQL Server 2016中的本机JSON支持

JSON_QUERY函数 (JSON_QUERY Function)

JSON_QUERY function will extract and return details as an array string from a given JSON string. In order to illustrate this we will use the same JSON string which we used in the previous example.

JSON_QUERY函数将从指定的JSON字符串中提取细节并将其作为数组字符串返回。 为了说明这一点,我们将使用与先前示例相同的JSON字符串。

 
SELECT JSON_QUERY(@vJson,'$.EmployeeInfo')
SELECT JSON_QUERY(@vJson,'$.Dependants')
SELECT JSON_QUERY(@vJson,'$.Dependants[0]') 
 
           

The first query will return details which is under EmployeeInfo path.

第一个查询将返回EmployeeInfo路径下的详细信息。

 
{"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		}
 
           

The second query will return details which is under Dependents path.

第二个查询将返回在Dependents路径下的详细信息。

 
[
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		] 
 
           

The third query will return details related to the first element under Dependants path. Hence it will return only the first detail set unlike the one above.

第三个查询将在Dependents路径下返回与第一个元素相关的详细信息。 因此,与上述方法不同,它将仅返回第一个详细信息集。

 
{"DepType":"Wife","DepName":"Jane","DepAge":30}
 
           

JSON_MODIFY函数 (JSON_MODIFY Function)

This is very similar to the xml.modify() functionality available in SQL Server. JSON_MODIFY function will be used to append an existing value on a property in a JSON string. Even though the name reflects an idea of modifying an existing value, it can be used in three ways.

这与SQL Server中提供的xml.modify()功能非常相似。 JSON_MODIFY函数将用于将现有值附加到JSON字符串中的属性上。 即使名称反映了修改现有值的想法,也可以通过三种方式使用它。

  • To update a value

    更新值

  • To delete a value

    删除值

  • To insert a value

    插入值

使用JSON_MODIFY函数更新JSON字符串的属性值 (Update a property value on JSON string using JSON_MODIFY function)

First, we will see how we can update an existing JSON property value using JSON_MODIFY function. You need to provide two things when updating.

首先,我们将看到如何使用JSON_MODIFY函数更新现有的JSON属性值。 更新时,您需要提供两件事。

  • Exact path of the property

    物业的确切路径

  • The value which should be updated.

    该值应被更新。

Example: 例:

We will consider the same JSON details which we used above and update the first name and the last name to ‘James Williams’ respectively.

我们将考虑与上述相同的JSON详细信息,并将名字和姓氏分别更新为“ James Williams”。

 
DECLARE @vJson AS NVARCHAR(4000) = N'{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		]}'
 
SELECT	
	@vJson = JSON_MODIFY(@vJson,'$.EmployeeInfo.FirstName','James')
	,@vJson = JSON_MODIFY(@vJson,'$.EmployeeInfo.LastName','Williams')
SELECT JSON_QUERY(@vJson,'$.EmployeeInfo')
 
           

When the aforementioned query is executed you will see the following in the results pane.

执行上述查询后,您将在结果窗格中看到以下内容。

 
{"FirstName": "James",	"LastName": "Williams",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		}
 
           

使用JSON_MODIFY函数删除JSON字符串上的属性值 (Delete a property value on JSON string using JSON_MODIFY function)

Now we will see how we can remove a property from an existing JSON string. Compared to the above update example, the only difference you could see is that the second parameter needs to be passed as NULL. We will take the same example above and will remove the property ‘AnnualSalary’

现在,我们将看到如何从现有的JSON字符串中删除属性。 与上面的更新示例相比,您可以看到的唯一区别是第二个参数需要作为NULL传递。 我们将采用与上面相同的示例,并将删除属性“ AnnualSalary”

 
DECLARE @vJson AS NVARCHAR(4000) = N'{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		]}'
 
SELECT	
	@vJson = JSON_MODIFY(@vJson,'$.EmployeeInfo.AnnualSalary',NULL)
PRINT @vJson  
 
           

Printing the value stored in @vJson variable will show that the property ‘AnnualSalary’ has been completely removed.

打印存储在@vJson变量中的值将显示属性“ AnnualSalary”已被完全删除。

 
{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970"
		},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		]}
 
           

使用JSON_MODIFY函数将属性插入JSON字符串 (Insert a property into a JSON string using JSON_MODIFY function)

Now we will see an example on how we can insert a property into an existing JSON string. When inserting a property the syntax is similar as updating a JSON string, but the path provided should not exist in the JSON. Otherwise, the function will behave as the JSON_MODIFY has been used for modifying the existing an existing property. Hence it will replace the value under the provided path instead of inserting a new property.

现在,我们将看到一个有关如何将属性插入现有JSON字符串的示例。 插入属性时,语法类似于更新JSON字符串,但是JSON中不应存在提供的路径。 否则,该函数将表现为JSON_MODIFY已用于修改现有的现有属性。 因此,它将替换提供的路径下的值,而不是插入新属性。

When it comes for insertion, there are two ways where a value can be inserted into a JSON string.

插入时,有两种方法可以将值插入JSON字符串。

  • Can be inserted as a Property/Value

    可以作为属性/值插入

  • Can be inserted as a new array element

    可以作为新的数组元素插入

We will see how we can use both these methods.

我们将看到如何使用这两种方法。

Inserting a new Property/Value to a JSON. 将新的Property / Value插入JSON。

We will use the same example JSON which we have been using in the previous examples and will insert a property called, ‘Doj’. (‘Doj’ denotes Date of Join)

我们将使用与先前示例相同的示例JSON,并将插入一个名为“ Doj”的属性。 (“ Doj”表示加入日期)

 
DECLARE @vJson AS NVARCHAR(4000) = N'{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		]}'
 
SELECT	
	@vJson = JSON_MODIFY(@vJson,'$.EmployeeInfo.Doj','12-Jun-2012')
PRINT @vJson 
 
           

Once you execute the aforementioned code snippet you can see that a new property has been added.

执行上述代码段后,您可以看到已添加了新属性。

 
{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		,"Doj":"12-Jun-2012"},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		]}
 
           
Inserting a new value to a JSON as a new element. 将新值作为新元素插入JSON。

The other way of inserting a new value to an existing JSON is to add it as a new element. This can be done using the following syntax. We will use the same example and will add a new dependent.

将新值插入现有JSON的另一种方法是将其添加为新元素。 可以使用以下语法完成此操作。 我们将使用相同的示例,并将添加一个新的依赖项。

 
DECLARE @vJson AS NVARCHAR(4000) = N'{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		]}'
 
SELECT	
	@vJson = JSON_MODIFY(@vJson,'append $.Dependants',JSON_QUERY('{"DepType": "Daughter","DepName": "Jenny","DepAge": 9}'))
PRINT @vJson 
 
           

But if you execute the above syntax, you will see that a new element will be added to the JSON string, but with lots of escape characters along with the double quotation character.

但是,如果执行上述语法,您将看到一个新元素将添加到JSON字符串中,但其中包含许多转义字符以及双引号字符。

 
{
		"EmployeeInfo": {"FirstName": "John",	"LastName": "Doe",
			"Dob": "12-Jan-1970",	"AnnualSalary": 85000
		},
		"Dependants": [
			{"DepType":"Wife","DepName":"Jane","DepAge":30}, 
			{"DepType": "Son","DepName": "James","DepAge": 12}
		,"{\"DepType\": \"Daughter\",\"DepName\": \"Jenny\",\"DepAge\": 9}"]}
 
           

This is normal as it’s explained in MSDN regarding this automatic escape characters. In order to add new elements without the automatic escape characters, wrap the value with the JSON_QUERY function like shown below.

这是正常现象,因为在MSDN中对此自动转义字符进行了说明。 为了添加没有自动转义字符的新元素,请使用JSON_QUERY函数包装值,如下所示。

 
SELECT	
	@vJson = JSON_MODIFY(@vJson,'append $.Dependants',JSON_QUERY('{"DepType": "Daughter","DepName": "Jenny","DepAge": 9}'))
PRINT @vJson 
 
           

You can find more details regarding this here – JSON_MODIFY (Transact-SQL)

您可以在此处找到有关此内容的更多详细信息– JSON_MODIFY(Transact-SQL)

OPENJSON函数 (OPENJSON Function)

Unlike the functions explained previously OPENJSON is a table valued function. Which means it will return a table or a collection of rows, rather than single value. This will iterate through JSON object arrays and populate a row for each element.

与前面介绍的函数不同,OPENJSON是一个表值函数。 这意味着它将返回一个表或行的集合,而不是单个值。 这将遍历JSON对象数组,并为每个元素填充一行。

This function will return the details as a result set containing the following information.

此函数将返回详细信息作为包含以下信息的结果集。

  • Key → Key name of the attribute 键→属性的键名称
  • Value → Value underlying the above key 值→上述键的基础值
  • Type → Data type of the value 类型→值的数据类型

This can be used in two ways.

这可以两种方式使用。

  • Without a pre-defined schema

    没有预定义的架构

  • With a well-defined schema

    具有明确定义的架构

在没有预定义架构的情况下使用OPENJSON (Usage of the OPENJSON without a pre-defined schema)

In order to illustrate this, we will use a different JSON string than the one we have been using in our previous examples.

为了说明这一点,我们将使用与前面示例中使用的JSON字符串不同的JSON字符串。

 
DECLARE @vJson AS NVARCHAR(1000) = '
{
    "A Null Value":null,
    "String Value":"Some String Data",
    "Numeric Value": 1000.00,
    "Boolean Value": true,
    "Array Data":["A","B","C"],
    "Object Data":{"Key1":"Value1", "Key2":10}
    }'
  
SELECT * FROM OPENJSON(@vJson)   
 
           

Executing this will return the following result set

执行此操作将返回以下结果集

SQL Server 2016中的本机JSON支持

OPENJSON与已定义模式的用法 (Usage of the OPENJSON with a defined schema)

When we use this method, it’s mandatory to provide a list of column names along with the respective data types. One advantage we have using a well-defined schema over the previous method is the ability to generate a resultset containing different columns for each attribute value, and for column names can be customized as per our requirement.

使用此方法时,必须提供列名列表以及相应的数据类型。 与以前的方法相比,我们使用定义良好的架构的一个优点是能够为每个属性值生成包含不同列的结果集,并且可以根据我们的要求自定义列名。

We will use a more realistic JSON string and see how we could achieve this and first we will see how we can fetch the details without changing the column names. We have to pass the schema details as shown below.

我们将使用更现实的JSON字符串,并了解如何实现此目的,首先,我们将了解如何在不更改列名的情况下获取详细信息。 我们必须传递模式详细信息,如下所示。

 
DECLARE @vJson AS NVARCHAR(1000) = N'
{
	"OrdNo":"XQ2379",
    "OrdDate":"20161228",
    "CustNo": "CQ1298",
    "OrdVal": 12755.89
    }
';
  
SELECT * FROM OPENJSON(@vJson) WITH (
	OrdNo		VARCHAR(6)
	,OrdDate	SMALLDATETIME
	,CustNo	VARCHAR(6)
	,OrdVal	MONEY
)
 
           

Executing the aforementioned code will give the following result set

执行上述代码将得到以下结果集

 
OrdNo  OrdDate                 CustNo OrdVal
------ ----------------------- ------ --------
XQ2379 2016-12-28 00:00:00     CQ1298 12755.89
 
           

Now we will see how we can change the column names when we fetch the details using the OPENJSON function. It’s similar to the example shown previously. The difference here is that the column name should be the one which we require to be shown and after the respective data type, it should be followed by the exact JSON path. (**Note that the path is case sensitive) If you don’t provide the correct path, the result set will return a NULL under the respective column.

现在,我们将看到使用OPENJSON函数获取详细信息时如何更改列名称。 它类似于前面显示的示例。 此处的区别在于,列名应为我们要求显示的列名,并且在各个数据类型之后,应紧随其后的是确切的JSON路径。 ( **请注意,路径区分大小写 )如果没有提供正确的路径,结果集将在相应列下返回NULL。

 
DECLARE @vJson AS NVARCHAR(1000) = N'
{
	"OrdNo":"XQ2379",
    "OrdDate":"20161228",
    "CustNo": "CQ1298",
    "OrdVal": 12755.89
    }
';
  
SELECT * FROM OPENJSON(@vJson) WITH (
	[ORD_NO]		VARCHAR(6)		N'$.OrdNo'
	,[ORD_DATE]	SMALLDATETIME	N'$.OrdDate'
	,[CUST_NO]		VARCHAR(6)		N'$.CustNo'
	,[ORD_VALUE]	MONEY			N'$.OrdVal'
)
 
           

Executing the aforementioned code will give the following result set

执行上述代码将得到以下结果集

 
OrdNo  OrdDate                 CustNo OrdVal
------ ----------------------- ------ --------
XQ2379 2016-12-28 00:00:00     CQ1298 12755.89 
 
           

See the example below, which the path for the Order No is provided incorrectly.

请参阅下面的示例,该订单号的路径提供不正确。

 
DECLARE @vJson AS NVARCHAR(1000) = N'
{"OrdNo":"XQ2379","OrdVal": 12755.89}';
  
SELECT * FROM OPENJSON(@vJson) WITH (
	[ORD_NO]		VARCHAR(6)		N'$.OrdNO'
	,[ORD_VALUE]	MONEY			N'$.OrdVal'
)  
 
           
 
ORD_NO ORD_VALUE
------ ---------------------
NULL   12755.89
 
           

FOR JSON函数 (FOR JSON Function)

FOR JSON functionality is pretty much similar to the FOR XML functionality available in SQL Server. It’s used to export tabular data to JSON format.

FOR JSON功能与SQL Server中提供的FOR XML功能非常相似。 它用于将表格数据导出为JSON格式。

Each row is converted to a JSON object and data on cells will be converted to values on those respective JSON objects. Column names/aliases will be used as key names.

每行将转换为JSON对象,单元格上的数据将转换为相应JSON对象的值。 列名/别名将用作键名。

There are two ways which FOR JSON functionality can be used.

可以使用两种方式使用FOR JSON功能。

  • FOR JSON AUTO

    对于JSON AUTO

  • FOR JSON PATH

    JSON路径

对于JSON AUTO (FOR JSON AUTO)

The functionality is similar to FOR XML AUTO. FOR JSON AUTO will export the tabular data by automatically creating the nested JSON sub-arrays based on the table hierarchy used in the query.

该功能类似于FOR XML AUTO。 FOR JSON AUTO将根据查询中使用的表层次结构自动创建嵌套的JSON子数组,从而导出表格数据。

In order to illustrate the aforementioned, we will use a simple data structure consisting of some Order Details.

为了说明上述内容,我们将使用由一些“订单详细信息”组成的简单数据结构。

 
CREATE TABLE OrderHeader(
	OrderId		INT
	,OrderDate	SMALLDATETIME
	,CustNo		VARCHAR(6)
)
 
CREATE TABLE OrderDetails(
	OrderId		INT
	,ProdNo		VARCHAR(6)
	,Qty		INT
	,Price		MONEY
	,LineTotal	MONEY
)
 
INSERT INTO dbo.OrderHeader
        (OrderId, OrderDate, CustNo)
VALUES (1,'27-Dec-2016','CQ1234')
 
INSERT INTO dbo.OrderDetails(
	OrderId
    ,ProdNo
    ,Qty
    ,Price
    ,LineTotal
)
VALUES(1,'101010',2,150,300),(1,'202020',1,147.50,147.50)
 
           

Execute the following query

执行以下查询

 
SELECT 
	OH.OrderId
   ,OH.OrderDate
   ,OH.CustNo
   ,OD.ProdNo
   ,OD.Qty
   ,OD.Price
   ,OD.LineTotal
FROM
	dbo.OrderHeader AS OH
	JOIN dbo.OrderDetails AS OD
		ON OD.OrderId = OH.OrderId
FOR JSON AUTO 
 
           

Executing the aforementioned query will produce the following result.

执行上述查询将产生以下结果。

 
[{
	"OrderId": 1,
	"OrderDate": "2016-12-27T00:00:00",
	"CustNo": "CQ1234",
	"OD": [{
		"ProdNo": "101010",
		"Qty": 2,
		"Price": 150.0000,
		"LineTotal": 300.0000
	}, {
		"ProdNo": "202020",
		"Qty": 1,
		"Price": 147.5000,
		"LineTotal": 147.5000
	}]
}]
 
           

Since we haven’t used any column aliases, the exact column names have been used as keys. If we use columns aliases the aliases will be used as attribute keys. Please refer to the below example:

由于我们没有使用任何列别名,因此将确切的列名用作键。 如果我们使用列别名,则别名将用作属性键。 请参考以下示例:

 
SELECT 
	OH.OrderId AS OrdId ,OH.OrderDate AS OrdDate
   ,OH.CustNo AS CustomerNo, OD.ProdNo AS PrdNo
   ,OD.Qty  AS PrdQty ,OD.Price AS PrdPrice, OD.LineTotal AS PrdTotal
FROM dbo.OrderHeader AS OH
	JOIN dbo.OrderDetails AS OD ON OD.OrderId = OH.OrderId
FOR JSON AUTO  
 
           

Executing the aforementioned query will give the following results.

执行上述查询将得到以下结果。

 
[{
	"OrdId": 1,
	"OrdDate": "2016-12-27T00:00:00",
	"CustomerNo": "CQ1234",
	"OD": [{
		"PrdNo": "101010",
		"PrdQty": 2,
		"PrdPrice": 150.0000,
		"PrdTotal": 300.0000
	}, {
		"PrdNo": "202020",
		"PrdQty": 1,
		"PrdPrice": 147.5000,
		"PrdTotal": 147.5000
	}]
}]
 
           

Please observe how the column aliases have been used as attribute keys.

请观察列别名如何用作属性键。

In both examples which have been illustrated for FOR JSON AUTO, you can see that the produced JSON doesn’t contain a root element. This is due to the fact that we haven’t given instruction to FOR JSON to export the result with a root element. We can export the details with a root element as follows:

在为FOR JSON AUTO演示的两个示例中,您可以看到生成的JSON不包含根元素。 这是由于我们尚未向FOR JSON发出指令以使用根元素导出结果。 我们可以使用根元素导出详细信息,如下所示:

 
SELECT 
	OH.OrderId AS OrdId ,OH.OrderDate AS OrdDate
   ,OH.CustNo AS CustomerNo, OD.ProdNo AS PrdNo
   ,OD.Qty  AS PrdQty ,OD.Price AS PrdPrice, OD.LineTotal AS PrdTotal
FROM dbo.OrderHeader AS OH
	JOIN dbo.OrderDetails AS OD ON OD.OrderId = OH.OrderId
FOR JSON AUTO, ROOT ('OrderInfo')
 
           
 
{
	"OrderInfo": [{
		"OrdId": 1,
		"OrdDate": "2016-12-27T00:00:00",
		"CustomerNo": "CQ1234",
		"OD": [{"PrdNo": "101010","PrdQty": 2,"PrdPrice": 150.0000,
			"PrdTotal": 300.0000
		}, {"PrdNo": "202020","PrdQty": 1,"PrdPrice": 147.5000,
			"PrdTotal": 147.5000
		}]}]
}
 
           

JSON路径 (FOR JSON PATH)

In the previous example, you could see how the order line details were exported as a separated JSON object when combined with AUTO option.

在上一个示例中,您可以看到与AUTO选项结合使用时如何将订单行详细信息作为单独的JSON对象导出。

But using PATH option will extract the details in a way how the SELECT statement will fetch. That’s instead of fetching order line information as a separate object, it will return as two different elements, along with the Order Header information.

但是,使用PATH选项将以SELECT语句获取方式的方式提取详细信息。 这不是将订单行信息作为单独的对象来获取,而是作为两个不同的元素以及订单标题信息返回。

 
SELECT 
	OH.OrderId ,OH.OrderDate
   ,OH.CustNo, OD.ProdNo
   ,OD.Qty, OD.Price, OD.LineTotal
FROM dbo.OrderHeader AS OH
	JOIN dbo.OrderDetails AS OD ON OD.OrderId = OH.OrderId
FOR JSON PATH, ROOT ('OrderInfo')
 
           
 
{
	"OrderInfo": [{
		"OrderId": 1,
		"OrderDate": "2016-12-27T00:00:00",
		"CustNo": "CQ1234",
		"ProdNo": "101010",
		"Qty": 2,
		"Price": 150.0000,
		"LineTotal": 300.0000
	}, {
		"OrderId": 1,
		"OrderDate": "2016-12-27T00:00:00",
		"CustNo": "CQ1234",
		"ProdNo": "202020",
		"Qty": 1,
		"Price": 147.5000,
		"LineTotal": 147.5000
	}]
}
 
           

However, there is one important thing, which you should be aware of when exporting details using FOR JSON PATH option. That is, if you happened to have the same column name on multiple tables you can only fetch one such column. If you include both these columns it will result in an error.

但是,有一件事很重要,在使用FOR JSON PATH选项导出详细信息时,您应该意识到这一点。 也就是说,如果您在多个表上碰巧具有相同的列名,则只能获取一个这样的列。 如果同时包含这两个列,将导致错误。

For example, if we try to export OrderId from both Header and Detail tables it will throw an error.

例如,如果我们尝试从Header和Detail表中导出OrderId,则将引发错误。

 
SELECT 
	OH.OrderId ,OH.OrderDate
   ,OH.CustNo, OD.OrderId, OD.ProdNo
   ,OD.Qty, OD.Price, OD.LineTotal
FROM dbo.OrderHeader AS OH
	JOIN dbo.OrderDetails AS OD ON OD.OrderId = OH.OrderId
FOR JSON PATH, ROOT ('OrderInfo') 
 
           
SQL Server 2016中的本机JSON支持

相关链接 (Related Links)

  • JSON Data (SQL Server) JSON数据(SQL Server)
  • Convert JSON Data to Rows and Columns with OPENJSON (SQL Server) 使用OPENJSON将JSON数据转换为行和列(SQL Server)
  • Format Query Results as JSON with FOR JSON (SQL Server) 使用FOR JSON将查询结果格式化为JSON(SQL Server)
翻译自: https://www.sqlshack.com/native-json-support-in-sql-server-2016/