SQL Server 2016 JSON原生支持实例说明

2023-05-16

背景

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可以使用索引进行优化。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL Server 2016 JSON原生支持实例说明 的相关文章

  • 数据库SQL语句中 查询选修了全部课程的学生的学号和姓名

    一 SQL语言查询选修了全部课程的学生的学号和姓名 两种解决途径 xff1a 第一种 xff1a 我们可以表示为在SC表中某个学生选修的课程数等于C表中课程总数 相应的SQL语言如下 xff1a select S xff0c SNAME f
  • 公钥与私钥,HTTPS详解

    1 公钥与私钥原理 1 鲍勃有两把钥匙 xff0c 一把是公钥 xff0c 另一把是私钥 2 鲍勃把公钥送给他的朋友们 帕蒂 道格 苏珊 每人一把 3 苏珊要给鲍勃写一封保密的信 她写完后用鲍勃的公钥加密 xff0c 就可以达到保密的效果
  • 321134

    13213131355555
  • add a private constructor to hide the implicit public one(Utility classes should not have public con...

    sonarlint提示add a private constructor to hide the implicit public one Utility classes should not have public constructors
  • 关于 OpenIdConnect 认证启用 HTTPS 回调 RedirectUri 不生效问题

    在搭建 IdentityServer 服务端后 xff0c 我们尝试使用了 OIDC OpenID Connect 的中间件来代替了原先的 Session 系统认证方式 xff0c 起初采用的是 HTTP 协议 xff0c 一切都没有什么问
  • Listview获取选中行的值

    一般情况请注意别先删除了选中行 xff0c 又去使用 那就会导致找不到选中行 哥犯了这个错误 找了很长时间问题 if this lstwlview SelectedIndices Count gt 0 if MessageBox Show
  • 红芯丑闻揭秘者 Touko 专访 | 关于红芯丑闻的更多内幕……

    专栏 九章算法 网址 www jiuzhang com 红芯事件 近日 xff0c 一则 自主研发的国产浏览器内核 xff0c 红芯宣布获2 5亿C轮融资 的讯息再次将 国产自主创新 这一话题推向高潮 xff0c 希冀之声群起 然好景不长
  • 腾讯广告广点通API接入文档(Android)

    官方文档地址 如果能够看懂文档的也没有必要再往下面看了 本篇文章就到此结束 下面记录的是本人在上面锁踩过的坑 xff0c 因为我发现Mac电脑上面的联系客服不是我想要的 本来只是内部使用的文档 xff0c 后来想想还是公开出来 xff0c
  • Spring Cloud整合Redis

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 项目需要使用Redis来做缓存 xff0c 研究了一下如何将其与Spring Boot整合 网上的demo要么就是太过于庞大 xff0c 要么就是版本过于陈旧 xff0c
  • logstash写入到kafka和从kafka读取日志

    收集nginx日志放到kafka 修改nginx日志格式 xff1a nginx日志格式修改 https blog 51cto com 9025736 2373483 input file type 61 gt 34 nginx acces
  • bootstrap轮播如何支持移动端滑动手势

    1 下载滑动手势 js 插件 xff1a hammer js cdn bootcss com hammer js 2 0 8 hammer min js 2 写一个javascript命令调用hammer js中的swipe功能 lt sc
  • 大家好,新年快乐。

    刚申请了个博客 xff0c 祝大家新年快乐 xff0d xff0d xff0d xff0d xff0d xff0d xff0d
  • SuSE下VNCVIEWER没有出现界面,只有shell窗口的问题

    首先正确配置 xff0c 打开vncserver xff1a 1 xff0c 实际上有三个服务 xff0c vnc1 xff0c vnc2 xff0c vnc3 xff0c 对应着三个服务 xff0c 先打开 可以直接在shell下输入 v
  • 35435354

    5435353534553
  • linux系统服务解析

    Linux系统服务解析 1 NetworaManager xff1a 在无线和有线网络之间快速切换 一般用于移动终端 2 NetworkManagerDispatcher xff1a 在多种网络环境之间来回切换 xff0c 与 Networ
  • 计算机主机的生产日期在哪里查,电脑生产日期怎么查

    大家好 xff0c 我是时间财富网智能客服时间君 xff0c 上述问题将由我为大家进行解答 1 利用键盘组合快捷键 Windows 43 R xff0c 打开 运行 输入 cmd xff0c 点确定 2 在弹出的命令提示符界面 xff0c
  • linux apache文件浏览器,在linux下使用Apache搭建文件服务器

    一 关于文件服务器 在一个项目中 xff0c 如果想把公共软件或者资料共享给项目组成员 xff0c 可以搭建一个简易的文件服务器来实现 xff0c 只要是在局域网内的成员都可以通过浏览器或者wget命令来下载和访问资料 可以达到信息共享 x
  • VUE开发常用组件收藏

    为什么80 的码农都做不了架构师 xff1f gt gt gt github地址 xff1a https github com opendigg awesome github vue UI组件开发框架实用库服务端辅助工具应用实例Demo示例
  • 【CDN 最佳实践】CDN缓存策略解读和配置策略

    CDN 作为内容分发网络主要是将资源缓存在 CDN 节点上 xff0c 然后后续访问即可直接通过 CDN 节点将资源返回给客户端 xff0c 而不再需要回到源站服务器以加快请求速度 那么 CDN 到底对于哪些请求加速呢 xff1f 其缓存规
  • dpkg参数

    dpkg 是Debian Package的简写 xff0c 是debian linus的安装格式 以下是一些 Dpkg 的用法 xff1a 1 dpkg i lt xxx deb gt 安装一个 Debian 软件包 2 dpkg c lt

随机推荐