SQL Server 2016 JSON原生支持實例說明

来源:http://www.cnblogs.com/wenBlog/archive/2016/08/29/5817842.html
-Advertisement-
Play Games

背景 Microsoft SQL Server 對於數據平臺的開發者來說越來越友好。比如已經原生支持XML很多年了,在這個趨勢下,如今也能在SQLServer2016中使用內置的JSON。尤其對於一些大數據很數據介面的環節來說這顯得非常有價值。與我們現在所做比如在SQL中使用CLR或者自定義的函數來 ...


背景

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_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

  

 

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

 

這個地方最關心就是查詢條件和添加索引。設想一下我們打算去查詢所有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可以使用索引進行優化。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.方法的命名規範,以NSString和NSMutableString為例如果方法是新創建的方法的第一個名字應該是其返回類型 + (instancetype)string; + (instancetype)stringWithString:(NSString *)string; + (instanc... ...
  • iOS系列 基礎篇 05 視圖鼻祖 - UIView 目錄: 在Cocoa和Cocoa Touch框架中,“根”類時NSObject類。同樣,在UIKit框架中,也存在一個神奇的類——UIView。 從繼承關係上看,UIView是所有視圖的根,我們形象地稱其為“始祖”。 本篇,咱們就一起研究UIVi ...
  • http://www.path8.net/tn/archives/951 MySQL支持大量的列類型,它可以被分為3類:數字類型、日期和時間類型以及字元串(字元)類型。本節首先給出可用類型的一個概述,並且總結每個列類型的存儲需求,然後提供每個類中的類型性質的更詳細的描述。概述有意簡化,更詳細的說明應 ...
  • 增加了一個Tools類,放了一些常用的工具 然後寫了一個比較通用的update方法 懶得寫測試類,肯定好使,相信我~ ...
  • 在使用sqlplus登錄資料庫的時候,輸入sys用戶名出現報錯 解決這個問題就是在輸入用戶名的時候加上as sysdba 這樣就不會出現上面ORA-28009:connection as sys should be as sysdba or sysoper ...
  • 前提條件: 1、Spark Standalone 集群部署完成 2、Intellij Idea 能夠運行 Spark local 模式的程式。 源碼: 這裡主要的思想還是將打包的jar提交到集群。 使用.setJars方法 ...
  • 一、 表設計 二、 索引 三、 SQL語句 四、 散表 五、 其他 FAQ 1-1.庫名、表名、欄位名必須使用小寫字母,“_”分割。 a)MySQL有配置參數lower_case_table_names,不可動態更改,linux系統預設為0,即庫表名以實際情況存儲,大小寫敏感。如果是1,以小寫存儲, ...
  • slave IO流程已經在http://www.cnblogs.com/onlyac/p/5815566.html中有介紹 這次我們要探索註冊slave請求和dump請求的報文格式和主要流程。 一、註冊slave請求 在slave IO連接完資料庫後,slave IO接著在主庫里註冊自己,以便後續不 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...