SQL Server 2016 JSON原生支持实例说明
背景
Microsoft SQL Server 对于数据平台的开发者来说越来越友好。比如已经原生支持XML很多年了,在这个趋势下,如今也能在SQLServer2016中使用内置的JSON。尤其对于一些大数据很数据接口的解析环节来说这显得非常有价值。与我们现在所做比如在SQL中使用CLR或者自定义的函数来解析JSON相比较,新的内置JSON会大大提高性能,同时优化了编程以及增删查改等方法。
那么是否意味着我们可以丢弃XML,然后开始使用JSON?当然不是,这取决于数据输出处理的目的。如果有一个外部的通过XML与外部交互数据的服务并且内外的架构是一致的,那么应该是使用XML数据类型以及原生的函数。如果是针对微型服务架构或者动态元数据和数据存储,那么久应该利用最新的JSON函数。
实例
当使用查询这些已经有固定架构的JSON的数据表时,使用“FOR JSON” 提示在你的T-SQL脚本后面,用这种方式以便于格式化输出。一下实例我使用了SQLServer 2016 Worldwide Importers sample database,可以在GitHub上直接下载下来(下载地址)。看一下视图Website.customers。我们查询一个数据并格式化输出JSON格式:
SELECT [CustomerID]
,[CustomerName]
,[CustomerCategoryName]
,[PrimaryContact]
,[AlternateContact]
,[PhoneNumber]
,[FaxNumber]
,[BuyingGroupName]
,[WebsiteURL]
,[DeliveryMethod]
,[CityName] ,DeliveryLocation.ToString() as DeliveryLocation
,[DeliveryRun]
,[RunPosition]
FROM [WideWorldImporters].[Website].[Customers]
WHERE CustomerID=1
FOR JSON AUTO
请注意我们有一个地理数据类型列(DeliveryLocation),这需要引入两个重要的变通方案(标黄):
首先,需要转换一个string字符,否则就会报错:
FOR JSON cannot serialize CLR objects. Cast CLR types explicitly into one of the supported types in FOR JSON queries.
其次,JSON采用键值对的语法因此必须指定一个别名来转换数据,如果失败会出现下面的错误:
Column expressions and data sources without names or aliases cannot be formatted as JSON text using FOR JSON clause. Add alias to the unnamed column or table.
确认了这些,改写的格式化输出如下:
[
{
"CustomerID": 1,
"CustomerName": "Tailspin Toys (Head Office)",
"CustomerCategoryName": "Novelty Shop",
"PrimaryContact": "Waldemar Fisar",
"AlternateContact": "Laimonis Berzins",
"PhoneNumber": "(308) 555-0100",
"FaxNumber": "(308) 555-0101",
"BuyingGroupName": "Tailspin Toys",
"WebsiteURL": "http://www.tailspintoys.com",
"DeliveryMethod": "Delivery Van",
"CityName": "Lisco",
"DeliveryLocation": "POINT (-102.6201979 41.4972022)",
"DeliveryRun": "",
"RunPosition": ""
}
]
当然也可以使用JSON作为输入型DML语句,例如INSERT/UPDATE/DELETE 语句中使用“OPENJSON”。因此可以在所有的数据操作上加入JSON提示。
如果不了解数据结构或者想让其更加灵活,那么可以将数据存储为一个JSON格式的字符类型,改列的类型可以使NVARCHAR 类型。Application.People 表中的CustomFields 列就是典型这种情况。可以用如下语句看一下表格格式这个列的内容:
declare @json nvarchar(max) SELECT @json=[CustomFields]
FROM [WideWorldImporters].[Application].[People]
where PersonID=8 select * from openjson(@json)
结果集在表格结果中的显示:

用另一种方式来查询这条记录,前提是需要知道在JSON数据结构和关键的名字,使用JSON_VALUE 和JSON_QUERY 函数:
SELECT
JSON_QUERY([CustomFields],'$.OtherLanguages') as OtherLanguages,
JSON_VALUE([CustomFields],'$.HireDate') as HireDate,
JSON_VALUE([CustomFields],'$.Title') as Title,
JSON_VALUE([CustomFields],'$.PrimarySalesTerritory') as PrimarySalesTerritory,
JSON_VALUE([CustomFields],'$.CommissionRate') as CommissionRate
FROM [WideWorldImporters].[Application].[People]
where PersonID=8
在表格结果集中展示表格格式的结果:

这个地方最关心就是查询条件和添加索引。设想一下我们打算去查询所有2011年以后雇佣的人,你可以运行下面的查询语句:
SELECT personID,fullName,JSON_VALUE(CustomFields,'$.HireDate') as hireDate
FROM [WideWorldImporters].[Application].[People]
where IsEmployee=1
and year(cast(JSON_VALUE(CustomFields,'$.HireDate') as date))>2011
切记JSON_VALUE 返回一个单一的文本值(nvarchar(4000))。需要转换返回值到一个时间字段中,然后分离年来筛选查询条件。实际执行计划如下:

为了验证如何对JSON内容创建索引,需要创建一个计算列。为了举例说明,Application.People 表标记版本,并且加入计算列,当系统版本为ON的时候不支持。我们这里使用Sales.Invoices表,其中ReturnedDeliveryData 中插入json数据。接下来获取数据,感受一下:
SELECT TOP 100 [InvoiceID]
,[CustomerID]
,JSON_QUERY([ReturnedDeliveryData],'$.Events')
FROM [WideWorldImporters].[Sales].[Invoices]
发现结果集第一个event都是“Ready for collection”:

然后获取2016年3月的发票数据:
SELECT [InvoiceID]
,[CustomerID]
,CONVERT(datetime, CONVERT(varchar,JSON_VALUE([ReturnedDeliveryData],'$.Events[0].EventTime')),126)
FROM [WideWorldImporters].[Sales].[Invoices]
WHERE CONVERT(datetime, CONVERT(varchar,JSON_VALUE([ReturnedDeliveryData],'$.Events[0].EventTime')),126)
BETWEEN '20160301' AND '20160331'
实际执行计划如下:

加入一个计算列叫做“ReadyDate”, 准备好集合表达式的结果:
ALTER TABLE [WideWorldImporters].[Sales].[Invoices]
ADD ReadyDate AS CONVERT(datetime, CONVERT(varchar,JSON_VALUE([ReturnedDeliveryData],'$.Events[0].EventTime')),126)
之后,重新执行查询,但是使用新的计算列作为条件:
SELECT [InvoiceID]
,[CustomerID]
,ReadyDate
FROM [WideWorldImporters].[Sales].[Invoices]
WHERE ReadyDate BETWEEN '20160301' AND '20160331'
执行计划是一样的,除了SSMS建议的缺失索引:

因此,根据建议在计算列上建立索引来帮助查询,建立索引如下:
/*
The Query Processor estimates that implementing the following index could improve the query cost by 99.272%.
*/
CREATE NONCLUSTERED INDEX IX_Invoices_ReadyDate
ON [Sales].[Invoices] ([ReadyDate])
INCLUDE ([InvoiceID],[CustomerID])
GO
我们重新执行查询验证执行计划:

有了索引之后,大大提升了性能,并且查询JSON的速度和表列是一样快的。
总结:
本篇通过对SQL2016 中的新增的内置JSON进行了简单介绍,主要有如下要点:
- JSON能在SQLServer2016中高效的使用,但是JSON并不是原生数据类型;
- 如果使用JSON格式必须为输出结果是表达式的提供别名;
- JSON_VALUE 和 JSON_QUERY 函数转移和获取Varchar格式的数据,因此必须将数据转译成你需要的类型。
- 在计算列的帮助下查询JSON可以使用索引进行优化。
SQL Server 2016 JSON原生支持实例说明的更多相关文章
- 三、SQL Server 对JSON的支持
一.SQL Server 对JSON的支持 一.实现效果 现在 我用数据库是sql2008 ,共计2万数据. 每一条数据里面的有一个为attribute字段是 json存储状态属性, 我怎么查看 ...
- sql server 2016 JSON 学习笔记
虽然现在win服务器已经几乎不用了,但是网上看到2016开始原生支持json 还是想试试 建立一个表 id int , json varchar(2000) json字段中输入数据 {"r ...
- SQL Server 2016原生支持JSON
转载原地址: http://www.cnblogs.com/lyhabc/p/4747694.html SQL Server 2005 开始支持 XML 数据类型,提供原生的 XML数据类型.XML ...
- SQL Server 2016新特性: 对JSON的支持
SQL Server 2005开始支持XML数据类型,提供原生的XML数据类型.XML索引及各种管理或输出XML格式的函数.随着JSON的流行,SQL Server2016开始支持JSON数据类 ...
- 数据库技术丛书:SQL Server 2016 从入门到实战(视频教学版) PDF
1:书籍下载方式: SQL Server2016从入门到实战 PDF 下载 链接:https://pan.baidu.com/s/1sWZjdud4RosPyg8sUBaqsQ 密码:8z7w 学习 ...
- SQL Server 2016 CTP2.2 的关键特性
SQL Server 2016 CTP2.2 的关键特性 正如微软CEO 说的,SQL Server2016 是一个Breakthrough Flagship Database(突破性的旗舰级数据库 ...
- SQL Server 2016的数据库范围内的配置
SQL Server 2016真的让人眼前一亮.几天前微软就提供了RCO(候选发布版)版本的下载.我已经围观了一圈RCO版本,其中一个最拽的功能是数据库范围内的配置(Database Scoped C ...
- .NET Core 1.1日期解析无APi、SQL Server数据转换JSON
前言 在批量导入Excel中的数据时发现出生日期为整数也就是为天数,结果倒腾了翻,这是其一,其二是数据库中的某一列存的是JSON数据,但是场景是为了作为作业来运行,此时不得不将筛选出的数据手动拼接成J ...
- SQL Server 2016 行级别权限控制
背景 假如我们有关键数据存储在一个表里面,比如人员表中包含员工.部门和薪水信息.只允许用户访问各自部门的信息,但是不能访问其他部门.一般我们都是在程序端实现这个功能,而在sqlserver2016以后 ...
随机推荐
- Go语言实战 - 我需要站内搜索
山坡网的用户抱怨"为什么搜索'二鬼子李富贵'找不到'二鬼子汉奸李富贵'?我用百度搜都能找到." 当时我就滴汗了,用户说的有道理,应该要能搜索到. 之前的方案很简单,用户输入的字串会 ...
- 使用python crontab设置linux定时任务
熟悉linux的朋友应该知道在linux中可以使用crontab设置定时任务.可以通过命令crontab -e编写任务.当然也可以直接写配置文件设置任务. 但是有时候希望通过脚本自动设置,比如我们应用 ...
- SQL Server 存储中间结果集
在SQL Server中执行查询时,有一些操作会产生中间结果集,例如:排序操作,Hash Join和Hash Aggregate操作产生的Hash Table,游标等,SQL Server查询优化器使 ...
- CSS系列目录
1. 在HTML中引入CSS的方法 2. CSS选择器 2.1 CSS3新增选择器 3. CSS的继承与层叠特性 4. CSS中盒子模型 5. CSS中盒子之间的关系 6. CSS中盒子的 ...
- 在ASP.NET中基于Owin OAuth使用Client Credentials Grant授权发放Token
OAuth真是一个复杂的东东,即使你把OAuth规范倒背如流,在具体实现时也会无从下手.因此,Microsoft.Owin.Security.OAuth应运而生(它的实现代码在Katana项目中),帮 ...
- Android开发之基本控件和详解四种布局方式
Android中的控件的使用方式和iOS中控件的使用方式基本相同,都是事件驱动.给控件添加事件也有接口回调和委托代理的方式.今天这篇博客就总结一下Android中常用的基本控件以及布局方式.说到布局方 ...
- Microsoft Build 2016 Day 1 记录
去年今日:Microsoft Build 2015 汇总 今年的 Bulid 时间是 3.30-4.1,第一天的主角主要是 Windows 10.人工智能.HoloLens.小娜等,详细介绍:3 分钟 ...
- 读书笔记--SQL必知必会09--汇总数据
9.1 聚集函数 聚集函数(aggregate function),对某些行运行的函数,计算并返回一个值. 使用聚集函数可以汇总数据而不必将涉及的数据实际检索出来. 可利用标准的算术操作符,实现更高级 ...
- 用CIL写程序:定义一个叫“慕容小匹夫”的类
前文回顾: <用CIL写程序:你好,沃尔德> <用CIL写程序:写个函数做加法> 前言: 今天是乙未羊年的第一天,小匹夫先在这里给各位看官拜个年了.不知道各位看官是否和匹夫一样 ...
- Lua 安全调用 metatable 的简单应用
事情的经过 我们的项目中存在好几个战斗界面,不过界面中的内容略有不同.跟同事出去吃饭的时候,他问我.我们现在的战斗界面.有很多是重复的,但是也有偶尔几个地方不太一样.我在战斗过程中驱动这些界面的时候. ...