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

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)

  

 

结果集在表格结果中的显示:

<span>SQL Server 2016 JSON原生支持实例说明</span>

 

用另一种方式来查询这条记录,前提是需要知道在JSON数据结构和关键的名字,使用JSON_VALUEJSON_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

  

 

在表格结果集中展示表格格式的结果:

<span>SQL Server 2016 JSON原生支持实例说明</span>

 

这个地方最关心就是查询条件和添加索引。设想一下我们打算去查询所有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))。需要转换返回值到一个时间字段中,然后分离年来筛选查询条件。实际执行计划如下:

<span>SQL Server 2016 JSON原生支持实例说明</span>

 

为了验证如何对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”:

<span>SQL Server 2016 JSON原生支持实例说明</span>

 

然后获取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'

  

实际执行计划如下:

<span>SQL Server 2016 JSON原生支持实例说明</span>

 

    加入一个计算列叫做“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建议的缺失索引:

<span>SQL Server 2016 JSON原生支持实例说明</span>

 

因此,根据建议在计算列上建立索引来帮助查询,建立索引如下:

/*
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

  

 

我们重新执行查询验证执行计划:

<span>SQL Server 2016 JSON原生支持实例说明</span>

 

有了索引之后,大大提升了性能,并且查询JSON的速度和表列是一样快的。

总结:

本篇通过对SQL2016 中的新增的内置JSON进行了简单介绍,主要有如下要点:

 

  • JSON能在SQLServer2016中高效的使用,但是JSON并不是原生数据类型;
  • 如果使用JSON格式必须为输出结果是表达式的提供别名;
  • JSON_VALUE 和 JSON_QUERY  函数转移和获取Varchar格式的数据,因此必须将数据转译成你需要的类型。
  • 在计算列的帮助下查询JSON可以使用索引进行优化。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119620.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • MySQL索引原理以及查询优化「建议收藏」

    一、介绍1.什么是索引?一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语

    2022年3月29日
    54
  • scrollHeight,clientHeight,scrollTop

    scrollHeight,clientHeight,scrollTop移动端加载数据时,由于数据太多,不会一次性全部加载出来。有些会采用pc端那样用分页码的形式,但是更多的确实滑动滚动条到内容最后,加载更多内容出来。一般引入了三方的前端框架和插件,基本都会有此功能。偶尔会需要采用原生js实现,故而此处就介绍下原生js的实现方式。另外附上jquery的实现方式。原生js实现思路需要三个高度:scrollHeight(文档内容实际高度,包括超出视窗的溢出部分)、scrollTop(滚动条滚动距离)、clientHeight(窗口可视范围高度)。当clientHeig

    2022年7月23日
    11
  • zigbee协议栈初使用(二)按键控制「建议收藏」

    zigbee协议栈初使用(二)按键控制「建议收藏」zigbee协议栈初使用(二)按键控制1、在hal_key.c中修改按键端口2、修改hal_board_cfg.h3、修改OnBoard.c,文件在ZMain.c目录下4、回到SampleApp.c,找到按键事件处理函数5、进入SampleApp_HandleKey()函数,此处是按键处理,按下按键需要做的事件放在这添加如下代码:此处…

    2022年5月8日
    65
  • 【ClassLoader】实现自定义类加载器加载指定路径下的Class文件和Jar包[通俗易懂]

    【ClassLoader】实现自定义类加载器加载指定路径下的Class文件和Jar包[通俗易懂]自定义类加载器:1.加载指定目录下的.class文件2.加载指定目录下的jar包

    2025年9月21日
    5
  • android studio输出文字_androiditem长按删除

    android studio输出文字_androiditem长按删除用EditText实现textView长按复制效果,edittexttextview首先EditText是集成TextView的我们直接将?EditText设置为不可编辑来实现其中重点为:android:background=”@null”//背景设为null,去掉editText下划线android:textCursorDrawable=”@null”//游标设为null,去掉游…

    2022年9月29日
    1
  • Anaconda详细安装及使用教程(带图文)

    Anacond的介绍Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。 因为包含了大量的科学包,Anaconda 的下载文件比较大(约 531MB),如果只需要某些包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版(仅包含conda和 Python)。Conda是一个开源的包、环境管理器,可以用于…

    2022年4月7日
    61

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号