为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 这个属性处理起来就比较麻烦了,性能也不见得好,所以小数据出来使用这个方法还是比较方便的。
相关文章推荐
- azure 云上 oracle11.2.0.4里dataguard归档日志传输 1034 问题详细解决过程
- ios Sqlite 的基本使用
- MySQL锁机制详解及死锁处理方式
- paoracle中的包头(Package)与包体(Package body)
- map同步数据库/后台缓存
- zabbix3.0 监控mysql服务免用户名密码登录的问题故障处理详细过程
- OneThink学习笔记02----数据字典(即OneThink项目数据库里的表及其字段)
- 实战体验几种MySQLCluster方案
- redis高可用方案Sentinel配置
- oracle中utl_file包读写文件操作实例学习
- 跟我一起学习MySQL技术内幕(第五版):(第三章学习日记3)
- Oracle的UTL_FILE.FOPEN学习笔记
- Ubuntu 安装 MongoDB
- Ubuntu 14.04下安装MySQL数据库
- node.js从数据库获取数据
- MySQL_Table_Index_Action
- MySQL_Table_View
- MySQL_View_Change
- MySQL_Trigger
- CentOS 7 配置Redis 并添加自启动服务