您的位置:首页 > 数据库

为sql server 增加 parseJSON 和 ToJSON 函数

2016-05-08 09:50 471 查看

在SqlServer中增加Json处理的方法

Sql Server 存储非结构话数据可以使用xml类型,使用xpath方式查询,以前写过一篇随笔:Sql Server xml 类型字段的增删改查

除了xml类型也可以使用文本类型(char、vchar等)存储json格式的数据,如何在sql语句中解析json数据,这里有一篇博客 [转]在SqlServer 中解析JSON数据,它的来源是 Consuming JSON Strings in SQL Server

针对json解析需要一个自定义类型Hierarchy、一个表值函数parseJSON、一个标量值函数ToJSON。语句如下:

/****** Object:  UserDefinedFunction [dbo].[ToJSON]    Script Date: 2016/5/6 17:25:49 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[ToJSON]
(
@Hierarchy Hierarchy READONLY
)

/*
the function that takes a Hierarchy table and converts it to a JSON string

Author: Phil Factor
Revision: 1.5
date: 1 May 2014
why: Added a fix to add a name for a list.
example:

Declare @XMLSample XML
Select @XMLSample='
<glossary><title>example glossary</title>
<GlossDiv><title>S</title>
<GlossList>
<GlossEntry ID="SGML" SortAs="SGML">
<GlossTerm>Standard Generalized Markup Language</GlossTerm>
<Acronym>SGML</Acronym>
<Abbrev>ISO 8879:1986</Abbrev>
<GlossDef>
<para>A meta-markup language, used to create markup languages such as DocBook.</para>
<GlossSeeAlso OtherTerm="GML" />
<GlossSeeAlso OtherTerm="XML" />
</GlossDef>
<GlossSee OtherTerm="markup" />
</GlossEntry>
</GlossList>
</GlossDiv>
</glossary>'

DECLARE @MyHierarchy Hierarchy -- to pass the hierarchy table around
insert into @MyHierarchy select * from dbo.ParseXML(@XMLSample)
SELECT dbo.ToJSON(@MyHierarchy)

*/
RETURNS NVARCHAR(MAX)--JSON documents are always unicode.
AS
BEGIN
DECLARE
@JSON NVARCHAR(MAX),
@NewJSON NVARCHAR(MAX),
@Where INT,
@ANumber INT,
@notNumber INT,
@indent INT,
@ii INT,
@CrLf CHAR(2)--just a simple utility to save typing!

--firstly get the root token into place
SELECT @CrLf=CHAR(13)+CHAR(10),--just CHAR(10) in UNIX
@JSON = CASE ValueType WHEN 'array' THEN
+COALESCE('{'+@CrLf+'  "'+NAME+'" : ','')+'['
ELSE '{' END
+@CrLf
+ CASE WHEN ValueType='array' AND NAME IS NOT NULL THEN '  ' ELSE '' END
+ '@Object'+CONVERT(VARCHAR(5),OBJECT_ID)
+@CrLf+CASE ValueType WHEN 'array' THEN
CASE WHEN NAME IS NULL THEN ']' ELSE '  ]'+@CrLf+'}'+@CrLf END
ELSE '}' END
FROM @Hierarchy
WHERE parent_id IS NULL AND valueType IN ('object','document','array') --get the root element
/* now we simply iterat from the root token growing each branch and leaf in each iteration. This won't be enormously quick, but it is simple to do. All values, or name/value pairs withing a structure can be created in one SQL Statement*/
SELECT @ii=1000
WHILE @ii>0
BEGIN
SELECT @where= PATINDEX('%[^[a-zA-Z0-9]@Object%',@json)--find NEXT token
IF @where=0 BREAK
/* this is slightly painful. we get the indent of the object we've found by looking backwards up the string */
SET @indent=CHARINDEX(CHAR(10)+CHAR(13),REVERSE(LEFT(@json,@where))+CHAR(10)+CHAR(13))-1
SET @NotNumber= PATINDEX('%[^0-9]%', RIGHT(@json,LEN(@JSON+'|')-@Where-8)+' ')--find NEXT token
SET @NewJSON=NULL --this contains the structure in its JSON form
SELECT
@NewJSON=COALESCE(@NewJSON+','+@CrLf+SPACE(@indent),'')
+CASE WHEN parent.ValueType='array' THEN '' ELSE COALESCE('"'+TheRow.NAME+'" : ','') END
+CASE TheRow.valuetype
WHEN 'array' THEN '  ['+@CrLf+SPACE(@indent+2)
+'@Object'+CONVERT(VARCHAR(5),TheRow.[OBJECT_ID])+@CrLf+SPACE(@indent+2)+']'
WHEN 'object' THEN '  {'+@CrLf+SPACE(@indent+2)
+'@Object'+CONVERT(VARCHAR(5),TheRow.[OBJECT_ID])+@CrLf+SPACE(@indent+2)+'}'
WHEN 'string' THEN '"'+dbo.JSONEscaped(TheRow.StringValue)+'"'
ELSE TheRow.StringValue
END
FROM @Hierarchy TheRow
INNER JOIN @hierarchy Parent
ON parent.element_ID=TheRow.parent_ID
WHERE TheRow.parent_id= SUBSTRING(@JSON,@where+8, @Notnumber-1)
/* basically, we just lookup the structure based on the ID that is appended to the @Object token. Simple eh? */
--now we replace the token with the structure, maybe with more tokens in it.
SELECT @JSON=STUFF (@JSON, @where+1, 8+@NotNumber-1, @NewJSON),@ii=@ii-1
END
RETURN @JSON
END

GO


toJson

在Sql查询中使用parseJSON和toJson方法

Sql Server xml 类型字段的增删改查 文章中介绍了几种用法,我这里非常简单。有一张表 Candidate_Ext,CVParseJson 字段存储了json格式数据,其中有个节点是SkillName存储了技能列表,这里使用sql语句把技能名称查出来逗号分隔。

"SkillList": [
{
"SkillId": 0,
"CandidateId": 0,
"TenantId": 0,
"SkillName": "Oracle",
"SkillLevel": 0,
"SkillLevelName": "熟练",
"SkillLevelName1": null
},
{
"SkillId": 0,
"CandidateId": 0,
"TenantId": 0,
"SkillName": "TCP/IP",
"SkillLevel": 0,
"SkillLevelName": "精通",
"SkillLevelName1": null
}
],


sql语句:

SELECT TOP 1 l.CandidateId ,l.CVParseJson,
( SELECT    StringValue+','
FROM      parseJSON(l.CVParseJson) json
WHERE  json.NAME='SkillName'
FOR
XML PATH('')
) 专业技能
FROM    dbo.Candidate_Ext l
WHERE   CVParseJson LIKE '{"candi%'


结果:

CandidateId    专业技能
1              Oracle,TCP/IP,


如果多个节点都有SkillName 这个属性处理起来就比较麻烦了,性能也不见得好,所以小数据出来使用这个方法还是比较方便的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: