SQL Server – Work with JSON

前言

JSON 是一个很好的格式, array, object 就能表达一个表格了.

如果想保存一些结构格式, 又不想用表格这么大费周章的话, JSON 会是很好选择.

比如我用它来记入 Audit Trial, 每一个请求的 post data 直接记入到一个 column 里面.

SQL Server 是在 2016 版本开始支持 JSON 格式的.

之前写过一些小笔记

 

主要参考

JSON data in SQL Server

Index JSON data

Format Query Results as JSON with FOR JSON (SQL Server)

YouTube – Deep dive: Using JSON with SQL Server (必看)

 

实战

创建 JSON Column

CREATE TABLE TestJson
(
    Id int IDENTITY CONSTRAINT PK_TestJson_Id PRIMARY KEY,
    JsonData nvarchar(max) CONSTRAINT [Content should be formatted as JSON] CHECK(ISJSON(JsonData)>0)
);

Json Column 其实就是 nvarchar 来的, 只是在上面加了一层 constraint 而已. ISJSON 是一个判断 text 是不是 JSON 的方法.

 

进资料

没什么特别的, 进 string 就可以了

INSERT INTO TestJson (JsonData) VALUES 
('{ "name": "Derrick", "age": 11, "good": true }'),
('{ "name": "Keatkeat", "age": 12, "good": false }');

 

OPENJSON

除了搞 table 还有一种简单的方式

复制代码
DECLARE @json NVARCHAR(MAX) = N'[
    {
        "name": "Derrick1"
    },
    {
        "name": "Derrick2"
    }
]';
SELECT * FROM OPENJSON(@json);
复制代码

result

OPENJSON 顾名思义, 就是把 JSON string 变成 table

然后就可以通过 JSON_VALUE(value, '$.name') 获取到 Derrick1.

value 是 column name 来的. (JSON_VALUE 的用法下面会教)

在一个例子

复制代码
DECLARE @json NVARCHAR(MAX) = N'{
    "products": [
        {
            "name": "Derrick"
        },
        {
            "name": "Derrick"
        }
    ]
}';
复制代码

我们拿 products 的 array 作为 table

SELECT * FROM OPENJSON(@json, '$.products');

$.products 就是获取 array 的路径

 

JSON_VALUE & JSON_QUERY

JSON_VALUE

SELECT 
JSON_VALUE(JsonData, '$.name')as [Name],
JSON_VALUE(JsonData, '$.age') as Age, 
CAST(JSON_VALUE(JsonData, '$.good') as bit) as Good, 
* FROM TestJson
WHERE JSON_VALUE(JsonData, '$.good') = 'true'
ORDER BY JSON_VALUE(JsonData, '$.name');

or

复制代码
DECLARE @json NVARCHAR(MAX) = N'[
    {
        "name": "Derrick1",
        "age": 1,
        "good": true
    },
    {
        "name": "Derrick1",
        "age": 1,
        "good": false
    }
]';

SELECT 
JSON_VALUE(value, '$.name')as [Name],
JSON_VALUE(value, '$.age') as Age, 
CAST(JSON_VALUE(value, '$.good') as bit) as Good FROM OPENJSON(@json)
WHERE JSON_VALUE(value, '$.good') = 'true'
ORDER BY JSON_VALUE(value, '$.name');
View Code
复制代码

通过 JSON_VALUE 这个方法可以获取到对象属性值, 然后就可以当成普通 column 值来处理了. 

注: boolean 被 parse 出来是 nvarchar 哦, 可以通过 cast 换成 bit. number parse 出来时 int, 这个是对的.

但是 JSON_VALUE 无法处理 Array 和 Object 哦

复制代码
DECLARE @json NVARCHAR(MAX) = N'[
    {
        "array": ["value1", "value2", "value3"],
        "obj": {
           "name": "Derrick"
        }
    }
]';

SELECT 
JSON_VALUE(value, '$.array'), --null
JSON_VALUE(value, '$.obj'), --null
JSON_VALUE(value, '$.obj.name'), --Derrick
JSON_VALUE(value, '$.array[0]') --value1
FROM OPENJSON(@json);
复制代码

如果最终值不是值类型, 那么就会输出 null.

JSON_QUERY

JSON_VALUE 无法输出 Object 和 Array, 而 JSON_QUERY 就可以. 

JSON_QUERY(value, '$.array'), --not null anymore
JSON_QUERY(value, '$.obj'), --not null anymore

result

where JSON Array contains value

复制代码
DECLARE @json NVARCHAR(MAX) = N'[
    {
        "array": ["value1", "value2", "value3"],
        "obj": {
           "name": "Derrick"
        }
    },
    {
        "array": ["value2", "value3"],
        "obj": {
           "name": "Derrick"
        }
    }
]';

SELECT * FROM OPENJSON(@json) WHERE (
  SELECT COUNT(*) FROM OPENJSON(JSON_QUERY([value], '$.array')) WHERE [value] = 'value1'
) > 0;
复制代码

运用了 JSON_QUERY 和 OPENJSON

不一定要使用子查询, 用 cross apply 也可以

 

Update

UPDATE TestJson SET JsonData = JSON_MODIFY(JsonData, '$.age', 100);

通过 JSON_MODIFY 就可以修改 JSON 内容了, 它会返回一个 JSON string, 有一种 immutable 的 feel...

如果要同时修改多个属性值也非常简单

UPDATE TestJson SET JsonData = JSON_MODIFY(JSON_MODIFY(JsonData, '$.age', 100), '$.good', 'false') ;

只要嵌套一下就可以了哦....

 

JSON Index

JSON 要 filter, orderby 快的话, 做法是通过 computed column 或者是索引来优化.

具体看这篇, 我就不写了.

 

Format to Json

把 query result serialize to json

FOR JSON AUTO

SELECT [Name], Sku, Price FROM Product FOR JSON AUTO, INCLUDE_NULL_VALUES;

result

[{"Name":"Product A","Sku":"SKU-1","Price":10},{"Name":"Product B","Sku":"SKU-2","Price":20}]

INCLUDE_NULL_VALUES 表示, 即使 value is null 也要输出 property. 默认 SQL Server 是不输出的 null 的哦

ROOT

SELECT [Name], Sku, Price FROM Product FOR JSON AUTO, ROOT('products'), INCLUDE_NULL_VALUES;

result

{"products":[{"Name":"Product A","Sku":"SKU-1","Price":10},{"Name":"Product B","Sku":"SKU-2","Price":20}]}

root 的作用是输出一个 wrapper

WITHOUT_ARRAY_WRAPPER

SELECT TOP 1 [Name], Sku, Price FROM Product FOR JSON AUTO, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER;

result

{"Name":"Product A","Sku":"SKU-1","Price":10}

默认情况 result 一定是 starts with bracket []. 如果我们确信输出的只有 1 个 value, 那么可以把 array bracket 去掉.

FOR JSON PATH

SELECT TOP 1 [Name] AS [Key.Name], SKU AS [Key.SKU], Price FROM Product FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER;

通过 [Key.Name], [Key.SKU] 可以把 2 个属性 wrap 起来

result

{"Key":{"Name":"Product A","SKU":"SKU-1"},"Price":10}

 

posted @   兴杰  阅读(365)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
点击右上角即可分享
微信分享提示