适用于:SQL Server 2016 (13.x)及更高版本
Azure SQL 数据库
Azure SQL 托管实例
Azure Synapse Analytics
Microsoft Fabric 中的 SQL 分析终结点
Microsoft Fabric 中的仓库
Microsoft Fabric 预览版中的 SQL 数据库
OPENJSON
表值函数分析 JSON 文本,并将 JSON 输入中的对象和属性作为行和列返回。 换句话说, OPENJSON
为 JSON 文档提供行集视图。 可以显式指定行集中的列以及用于填充列的 JSON 属性路径。 由于 OPENJSON
返回一组行,因此可以在 OPENJSON
Transact-SQL 语句的子句中使用 FROM
,就像可以使用任何其他表、视图或表值函数一样。
用于 OPENJSON
将 JSON 数据导入 SQL Server,或将 JSON 数据转换为不能直接使用 JSON 的应用或服务的关系格式。
Note
该 OPENJSON
函数仅在兼容级别 130 或更高版本下可用。 如果数据库兼容性级别低于 130,则 SQL Server 找不到并运行该 OPENJSON
函数。 其他 JSON 函数在所有兼容性级别均可用。
可以在 sys.databases
视图或数据库属性中查看兼容级别。 可以使用以下命令更改数据库的兼容级别:
ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130
Syntax
OPENJSON( jsonExpression [ , path ] ) [ <with_clause> ]
<with_clause> ::= WITH ( { colName type [ column_path ] [ AS JSON ] } [ ,...n ] )
OPENJSON
表值函数分析作为第一个参数提供的 jsonExpression,并返回一行或多行,其中包含表达式中 JSON 对象中的数据。
jsonExpression 可以包含嵌套的子对象。 如果要从 jsonExpression 中分析子对象,可以为 JSON 子对象指定 路径 参数。
openjson
默认情况下,OPENJSON
表值函数返回三列,其中包含 jsonExpression 中找到的每个key:value
对的键名称、值和类型。 或者,可以通过提供with_clause显式指定返回的结果集OPENJSON
的架构。
with_clause
with_clause包含一个列列表,其中包含要OPENJSON
返回的列类型。 默认情况下,将 OPENJSON
jsonExpression 中的键与 with_clause 中的列名匹配(在本例中,匹配键表示区分大小写)。 如果列名与键名称不匹配,可以提供可选的column_path,这是引用 jsonExpression 中的键的 JSON 路径表达式。
Arguments
jsonExpression
是包含 JSON 文本的 Unicode 字符表达式。
OPENJSON 循环访问 JSON 表达式中的数组的元素或对象的属性,并为每个元素或属性返回一行。 以下示例返回作为 jsonExpression 提供的对象的每个属性:
DECLARE @json NVARCHAR(2048) = N'{
"String_value": "John",
"DoublePrecisionFloatingPoint_value": 45,
"DoublePrecisionFloatingPoint_value": 2.3456,
"BooleanTrue_value": true,
"BooleanFalse_value": false,
"Null_value": null,
"Array_value": ["a","r","r","a","y"],
"Object_value": {"obj":"ect"}
}';
SELECT * FROM OpenJson(@json);
Results:
关键值 | value | 类型 |
---|---|---|
String_value | John | 1 |
DoublePrecisionFloatingPoint_value | 45 | 2 |
DoublePrecisionFloatingPoint_value | 2.3456 | 2 |
BooleanTrue_value | true | 3 |
BooleanFalse_value | false | 3 |
Null_value | NULL | 0 |
Array_value | ["a","r","r","a","y"] | 4 |
Object_value | {"obj":"ect"} | 5 |
- DoublePrecisionFloatingPoint_value 遵循 IEEE-754。
path
引用 jsonExpression 中的对象或数组的可选 JSON 路径表达式。
OPENJSON
查找位于指定位置的 JSON 文本,并仅分析引用的片段。 有关详细信息,请参阅 JSON 路径表达式。
可以将变量作为 路径的值提供。 (SQL Server 2016(13.x)和早期版本中不支持此功能。
以下示例通过指定 路径返回嵌套对象:
DECLARE @json NVARCHAR(4000) = N'{
"path": {
"to":{
"sub-object":["en-GB", "en-UK","de-AT","es-AR","sr-Cyrl"]
}
}
}';
SELECT [key], value
FROM OPENJSON(@json,'$.path.to."sub-object"')
Results
Key | Value |
---|---|
0 | en-GB |
1 | en-UK |
2 | de-AT |
3 | es-AR |
4 | sr-Cyrl |
分析 JSON 数组时 OPENJSON
,该函数将 JSON 文本中元素的索引作为键返回。
用于将路径各步与 JSON 表达式的属性进行匹配的比较不区分大小写且无法识别排序规则(即是 BIN2 比较)。
数组元素标识
Azure Synapse Analytics 中的无服务器 SQL 池中的 OPENJSON
函数可以自动生成每一行的标识并作为结果返回。 在列定义后面的 JSON 路径中,使用表达式 $.sql:identity()
来指定标识列。 JSON 路径表达式中包含此值的列将为该函数所分析的 JSON 数组中的每个元素都生成一个唯一的基于 0 的数。 标识值表示数组元素的位置/索引。
DECLARE @array VARCHAR(MAX);
SET @array = '[{"month":"Jan", "temp":10},{"month":"Feb", "temp":12},{"month":"Mar", "temp":15},
{"month":"Apr", "temp":17},{"month":"May", "temp":23},{"month":"Jun", "temp":27}
]';
SELECT * FROM OPENJSON(@array)
WITH ( month VARCHAR(3),
temp int,
month_id tinyint '$.sql:identity()') as months
Results
month | temp | month_id |
---|---|---|
Jan | 10 | 0 |
Feb | 12 | 1 |
Mar | 15 | 2 |
Apr | 17 | 3 |
May | 23 | 4 |
Jun | 27 | 5 |
该标识仅在 Synapse Analytics 中的无服务器 SQL 池中可用。
with_clause
显式定义要返回的函数的 OPENJSON
输出架构。 可选 with_clause 可以包含以下元素:
colName
输出列的名称。
默认情况下, OPENJSON
使用列的名称来匹配 JSON 文本中的属性。 例如,如果在架构中指定列 name
, OPENJSON
则尝试使用 JSON 文本中的属性“name”填充此列。 可以使用 column_path 参数替代此默认映射。
type
输出列的数据类型。
Note
如果还使用该AS JSON
选项,则列数据类型必须为 nvarchar(MAX)。
column_path
是指定要在指定列中返回的属性的 JSON 路径。 有关详细信息,请参阅本主题前面 路径 参数的说明。
当输出列的名称与属性的名称不匹配时,请使用 column_path 替代默认映射规则。
用于将路径各步与 JSON 表达式的属性进行匹配的比较不区分大小写且无法识别排序规则(即是 BIN2 比较)。
有关路径的详细信息,请参阅 JSON 路径表达式。
AS JSON
AS JSON
使用列定义中的选项指定引用的属性包含内部 JSON 对象或数组。 如果指定AS JSON
该选项,则列的类型必须为 nvarchar(MAX)。
如果未为列指定
AS JSON
,该函数将从指定路径上的指定 JSON 属性返回标量值(例如 int、 string、 true、 false)。 如果路径表示对象或数组,并且无法在指定路径中找到该属性,则函数在模式中NULL
返回lax
或返回模式中的strict
错误。 此行为类似于函数的行为JSON_VALUE
。如果为列指定
AS JSON
,该函数将从指定路径上的指定 JSON 属性返回 JSON 片段。 如果路径表示标量值,并且无法在指定路径中找到该属性,则函数在模式中NULL
返回lax
或返回模式中的strict
错误。 此行为类似于函数的行为JSON_QUERY
。
Note
如果要从 JSON 属性返回嵌套 JSON 片段,则必须提供 AS JSON
标志。 如果没有此选项,如果找不到该属性, OPENJSON
则返回一个 NULL
值,而不是引用的 JSON 对象或数组,或者在模式下返回运行时错误 strict
。
例如,以下查询返回数组的元素并进行格式设置:
DECLARE @json NVARCHAR(MAX) = N'[
{
"Order": {
"Number":"SO43659",
"Date":"2011-05-31T00:00:00"
},
"AccountNumber":"AW29825",
"Item": {
"Price":2024.9940,
"Quantity":1
}
},
{
"Order": {
"Number":"SO43661",
"Date":"2011-06-01T00:00:00"
},
"AccountNumber":"AW73565",
"Item": {
"Price":2024.9940,
"Quantity":3
}
}
]'
SELECT *
FROM OPENJSON ( @json )
WITH (
Number VARCHAR(200) '$.Order.Number',
Date DATETIME '$.Order.Date',
Customer VARCHAR(200) '$.AccountNumber',
Quantity INT '$.Item.Quantity',
[Order] NVARCHAR(MAX) AS JSON
)
Results
Number | Date | Customer | Quantity | Order |
---|---|---|---|---|
SO43659 | 2011-05-31T00:00:00 | AW29825 | 1 | {"Number":"SO43659","Date":"2011-05-31T00:00:00"} |
SO43661 | 2011-06-01T00:00:00 | AW73565 | 3 | {"Number":"SO43661","Date":"2011-06-01T00:00:00"} |
Return value
函数返回的列 OPENJSON
取决于 WITH
该选项。
使用默认架构进行调用
OPENJSON
时(即未在WITH
子句中指定显式架构时)函数将返回具有以下列的表:Key
. 一个 nvarchar(4000) 值,该值包含指定数组中元素的指定属性的名称或索引。 该key
列具有 BIN2 排序规则。Value
. 一个包含属性值的 nvarchar(MAX) 值。 该value
列从 jsonExpression 继承其排序规则。Type
. 一个包含值类型的 int 值。Type
仅当与默认架构一起使用OPENJSON
时,才会返回该列。 该type
列具有以下值之一:类型列的值 JSON 数据类型 0 null 1 字符串 2 number 3 true/false 4 数组 5 对象
仅返回第一级属性。 如果 JSON 文本的格式不正确,则语句会失败。
在子句中
OPENJSON
调用WITH
并指定显式架构时,该函数将返回一个表,其中包含在子句中WITH
定义的架构。
Note
仅当与默认架构一起使用Key
并且不能与显式架构一起使用时,才会返回列Value
Type
OPENJSON
和列。
Remarks
在with_clause的第二个参数OPENJSON
或with_clause中使用的json_path可以从或strict
关键字开始lax
。
- 在
lax
模式下,如果找不到指定路径上的对象或值,OPENJSON
则不会引发错误。 如果找不到路径,OPENJSON
则返回空结果集或NULL
值。 - 在
strict
模式中,OPENJSON
如果找不到路径,则返回错误。
此页上的一些示例显式指定路径模式, lax
或 strict
。 路径模式是可选项。 如果未显式指定路径模式, lax
则模式为默认值。 有关路径模式和路径表达式的详细信息,请参阅 JSON 路径表达式。
with_clause中的列名与 JSON 文本中的键匹配。 如果指定列名 [Address.Country]
,则它会与键 Address.Country
进行匹配。 如果要在对象 Country
中引用嵌套键 Address
,则必须在列路径中指定路径 $.Address.Country
。
json_path 可以包含包含字母数字字符的键。 如果键中有特殊字符,请使用双引号转义 json_path 中的键名称。 例如, $."my key $1".regularKey."key with . dot"
匹配以下 JSON 文本中的值 1
:
{
"my key $1": {
"regularKey":{
"key with . dot": 1
}
}
}
Examples
示例 1 - 将 JSON 数组转换为临时表
下面的示例以 JSON 数字数组的形式提供标识符的列表。 查询将 JSON 数组转换为标识符表,并筛选有指定 ID 的所有产品。
DECLARE @pSearchOptions NVARCHAR(4000) = N'[1,2,3,4]'
SELECT *
FROM products
INNER JOIN OPENJSON(@pSearchOptions) AS productTypes
ON product.productTypeID = productTypes.value
此查询与下面的示例等效。 但是在下面的示例中,必须在查询中嵌入数字而不是将它们作为参数进行传递。
SELECT *
FROM products
WHERE product.productTypeID IN (1,2,3,4)
示例 2 - 合并来自两个 JSON 对象的属性
下面的示例选择两个 JSON 对象的所有属性的并集。 这两个对象具有重复 的名称 属性。 该示例使用键值从结果中排除重复行。
DECLARE @json1 NVARCHAR(MAX),@json2 NVARCHAR(MAX)
SET @json1=N'{"name": "John", "surname":"Doe"}'
SET @json2=N'{"name": "John", "age":45}'
SELECT *
FROM OPENJSON(@json1)
UNION ALL
SELECT *
FROM OPENJSON(@json2)
WHERE [key] NOT IN (SELECT [key] FROM OPENJSON(@json1))
示例 3 - 使用 CROSS APPLY 联接包含存储在表单元格中的 JSON 数据的行
在下面的示例中,SalesOrderHeader
表具有一个 SalesReason
文本列,它包含采用 JSON 格式的 SalesOrderReasons
的数组。 这些 SalesOrderReasons
对象包含 质量 与 制造商等属性。 该示例创建一个报表,它将每个销售订单行联接到相关销售原因。 运算符 OPENJSON
扩展销售原因的 JSON 数组,就像原因存储在单独的子表中一样。 然后, CROSS APPLY
运算符将每个销售订单行联接到表值函数返回的 OPENJSON
行。
SELECT SalesOrderID,OrderDate,value AS Reason
FROM Sales.SalesOrderHeader
CROSS APPLY OPENJSON(SalesReasons)
Tip
如果必须扩展存储在各个字段中的 JSON 数组并将其与其父行联接,则通常使用 Transact-SQL CROSS APPLY
运算符。 有关详细信息 CROSS APPLY
,请参阅 FROM 子句。
可以通过将 OPENJSON
与要返回的行的显式定义架构一起使用,来重写相同查询:
SELECT SalesOrderID, OrderDate, value AS Reason
FROM Sales.SalesOrderHeader
CROSS APPLY OPENJSON (SalesReasons) WITH (value NVARCHAR(100) '$')
在此示例中,$
路径引用数组中的每个元素。 如果要显式强制转换返回值,则可以使用此类型的查询。
示例 4 - 使用 CROSS APPLY 合并关系行和 JSON 元素
以下查询将关系行和 JSON 元素合并到下表中显示的结果中。
SELECT store.title, location.street, location.lat, location.long
FROM store
CROSS APPLY OPENJSON(store.jsonCol, 'lax $.location')
WITH (street VARCHAR(500) , postcode VARCHAR(500) '$.postcode' ,
lon int '$.geo.longitude', lat int '$.geo.latitude')
AS location
Results
title | street | postcode | lon | lat |
---|---|---|---|---|
全食品市场 | 17991 雷德蒙德路 | WA 98052 | 47.666124 | -122.10155 |
Sears | 第 148 大道 NE | WA 98052 | 47.63024 | -122.141246,17 |
示例 5 - 将 JSON 数据导入 SQL Server 中
下面的示例展示了将整个 JSON 对象加载到 SQL Server 表中。
DECLARE @json NVARCHAR(max) = N'{
"id" : 2,
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"dateOfBirth": "2015-03-25T12:00:00",
"spouse": null
}';
INSERT INTO Person
SELECT *
FROM OPENJSON(@json)
WITH (id INT,
firstName NVARCHAR(50), lastName NVARCHAR(50),
isAlive BIT, age INT,
dateOfBirth DATETIME, spouse NVARCHAR(50))
示例 6 - 使用 JSON 内容的简单示例
--simple cross apply example
DECLARE @JSON NVARCHAR(MAX) = N'[
{
"OrderNumber":"SO43659",
"OrderDate":"2011-05-31T00:00:00",
"AccountNumber":"AW29825",
"ItemPrice":2024.9940,
"ItemQuantity":1
},
{
"OrderNumber":"SO43661",
"OrderDate":"2011-06-01T00:00:00",
"AccountNumber":"AW73565",
"ItemPrice":2024.9940,
"ItemQuantity":3
}
]'
SELECT root.[key] AS [Order],TheValues.[key], TheValues.[value]
FROM OPENJSON ( @JSON ) AS root
CROSS APPLY OPENJSON ( root.value) AS TheValues