将SQL Server的任意记录转换为JSON格式(JQGRID) -- 支持SQL 2005

2023-05-16

从SQL 2008开始,SQL Sever已经支持JSON数据,SQL 2016已经对JSON数据的处理支持非常完善。

对于SQL 2016以上版本的用户,可以直接调用原生方法,效率更高。


因客户采用SQL 2005,为了做到通用,特地写了以下存储过程,效率不差。

CREATE PROCEDURE[dbo].[GetJqgridJson](
	@ParameterSQL AS NVARCHAR(MAX),	--SQL SELECT语句(可加条件)
	@page INT = 1,	--页码
	@rows int = 10,	--每页记录数
	@soid nvarchar(100) = N'idSort'		--排序字段
)
AS
--作用:将查询记录转换为JQGRID的JSON字符串,兼容SQL 2005。
--建议:SQL2008开始已经对JSON的原生支持,SQL2016对JSON支持已经完善。建议高版本的SQL采用原生的支持
--调用方法:
----EXEC dbo.GetJqgridJson 'select * from table where 条件 ......', 页码, 每页记录数, '排序字段'
--返回 json字段
--限制:@ParameterSQL中不应该存在Json_Row和idSort字段,字段值中不能包含'<[":TmplateString:"]>'字符

如果只是为了将记录转换为通用JSON,可以稍微修改下the_End:标号下面的处理过程,入参也可以自行调整。

存储过程中采用了动态SQL生成全局临时表,用于数据结构的抽取。

采用按数据行处理数据,提高处理效率,特别适合于小数据量的处理(如为JQGrid提供后台JSON数据)


CREATE PROCEDURE[dbo].[GetJqgridJson](
	@ParameterSQL AS NVARCHAR(MAX),	--SQL SELECT语句(可加条件)
	@page INT = 1,	--页码
	@rows INT = 10,	--每页记录数
	@soid nvarchar(100) = N'idSort'		--排序字段
)
AS
--作用:将查询记录转换为JQGRID的JSON字符串,兼容SQL 2005。
--建议:SQL2008开始已经对JSON的原生支持,SQL2016对JSON支持已经完善。建议高版本的SQL采用原生的支持
--调用方法:
----EXEC dbo.GetJqgridJson 'select * from table where 条件 ......', 页码, 每页记录数, '排序字段'
--返回 json字段
--限制:@ParameterSQL中不应该存在Json_Row和idSort字段,字段值中不能包含'<[":TmplateString:"]>'字符
BEGIN
SET NOCOUNT ON
--CEILING(@rowcount/@rows)得到总页数,但两数相除必须起码其中一个为非整数方可得小数,两INT相除得向下取整的整数
declare @rowcount decimal(10,0)	
declare @current_row int = 1
DECLARE @JSON NVARCHAR(MAX) = ''
DECLARE @SQL NVARCHAR(MAX)


--取得总记录数
SET @Sql = 'SET @rowcount = (SELECT COUNT(*) FROM (' + @ParameterSQL + ') A)' 
EXEC SP_EXECUTESQL @Sql, N'@rowcount INT OUTPUT', @rowcount OUTPUT
IF @rowcount = 0
BEGIN
	GOTO the_End
END

DECLARE @total INT
DECLARE @records INT	--实际获取的记录数
SET @total = CEILING(@rowcount/@rows)
IF @page < @total 
	SET @records = @rows
ELSE
BEGIN
	SET @page = @total	--页码不能超过总页数
	SET @records = @rowcount - (@page - 1)*@rows	--末页的记录数
END

DECLARE @XMLString NVARCHAR(MAX)
DECLARE @XML XML

DECLARE @StartRoot VARCHAR(100);SET @StartRoot='<Json_Row>'
DECLARE @EndRoot VARCHAR(100);SET @EndRoot='</Json_Row>'

SET @SQL = 'SET @XML = (select * from ' +
	'(select ROW_NUMBER() over(order by t.[' + @soid + ']) as idSort, * from (' + @ParameterSQL + ') as t) A ' +
	'where A.idSort between ' + convert(varchar(10),(@page - 1) *@rows + 1) + ' and ' + convert(varchar(10), @page*@rows)
	+' FOR XML PATH(''Json_Row''))'
--PRINT @SQL		
EXEC sp_executesql @SQL, N'@XML XML OUTPUT', @XML OUTPUT
SET @XMLString=CAST(@XML AS NVARCHAR(MAX))
  
DECLARE @Row NVARCHAR(MAX)
DECLARE @RowTmp NVARCHAR(MAX)
DECLARE @RowStart INT
DECLARE @RowEnd INT
DECLARE @FieldStart INT = 0
DECLARE @FieldEnd INT = 0
DECLARE @KEY NVARCHAR(MAX)
DECLARE @Value NVARCHAR(MAX)
  

DECLARE @StartField NVARCHAR(100);SET @StartField='<'
DECLARE @EndField NVARCHAR(100);SET @EndField='>'
DECLARE @TemplateString VARCHAR(100) = '<[":TmplateString:"]>'


--提取数据结构
DECLARE @RndTableName VARCHAR(50)	--随机临时表名
SET @RndTableName = '##' + REPLACE(CONVERT(VARCHAR(50),NEWID()), '-','')
--if object_id('tempdb..##' + @RndTableName) is not null
--	drop table ##t1
SET @SQL = 'SELECT * INTO ' + @RndTableName + ' FROM (SELECT * FROM (' + @ParameterSQL + ') A WHERE 1=0) B'
EXEC(@SQL)

DECLARE @t2 TABLE(
	colname nvarchar(100),
	datatype varchar(100)
)
--INSERT @t2 values('idSort', 'int')
INSERT INTO @t2 SELECT c.name COLUMN_NAME, t.name DATA_TYPE
	FROM tempdb.dbo.syscolumns c, tempdb.dbo.systypes t
	WHERE c.xusertype = t.xusertype 
	AND c.id = object_id('tempdb..' + @RndTableName)

--删除临时表
SET @SQL = 'drop table ' + @RndTableName
EXEC (@SQL)

declare @colname nvarchar(100)
declare @datatype varchar(100)
  
SET @RowStart=CharIndex(@StartRoot,@XMLString,0)

DECLARE cur1 cursor SCROLL local       /* 声明游标,默认为 FORWARD_ONLY 游标  */ 
FOR SELECT colname, datatype FROM @t2 
OPEN cur1                 /* 打开游标  */ 

while @current_row <= @records
BEGIN
    SET @RowStart=@RowStart+Len(@StartRoot)
    SET @RowEnd=CharIndex(@EndRoot,@XMLString,@RowStart)
    SET @Row=SubString(@XMLString,@RowStart,@RowEnd-@RowStart)
    SET @JSON=@JSON+'{'
    
  
    -- for each row
    --移除idSort
	SET @FieldStart = CharIndex('<idSort>', @Row, 0) + LEN('<idSort>')
	SET @FieldEnd = CharIndex('</idSort>', @Row, @FieldStart)
	SET @Value = SubString(@Row, @FieldStart , @FieldEnd-@FieldStart)
	SET @Row =  replace(@Row, '<idSort>' + @Value + '</idSort>', '')

	FETCH FIRST from cur1 into @colname, @datatype    /* 读取第 1 行数据 */ 
	WHILE @@FETCH_STATUS = 0      /* 用 WHILE 循环控制游标活动  */ 
	BEGIN 
		--先替换空元素
		SET @RowTmp = @Row
		SET @Row = replace(@Row, '<' + @colname + '/>', '"' + @colname + '":' + '"",')
		IF @RowTmp = @Row
		BEGIN
			SET @Value = ''

			--替换有值元素
			SET @FieldStart = CharIndex('<' + @colname+ '>', @Row, 0) + LEN('<' + @colname + '>')
			SET @FieldEnd = CharIndex('</' + @colname + '>', @Row, @FieldStart)
			--取值
			IF @FieldEnd > @FieldStart
			BEGIN
				SET @Value = SubString(@Row, @FieldStart , @FieldEnd-@FieldStart)
				--临时用模板值代替
				SET @Row =  replace(@Row, '<' + @colname + '>' + @Value + '</' + @colname + '>', @TemplateString)

				--处理各种不同类型的值
				IF (@datatype='date' OR @datatype='datetime')
					SET @Value = replace(@Value, 'T', ' ')
				--TODO: 处理其他数据类型?
				ELSE
				BEGIN
					--处理值中的特殊字符
					SET @Value = replace(@Value, '\', '\\')	--\
					SET @Value = replace(@Value, '''', '\''')	--'
					SET @Value = replace(@Value, '"', '\"')	--"
					SET @Value = replace(@Value, '&', '\&')	--&
					SET @Value = replace(@Value, char(9), '\t')	--制表
					SET @Value = replace(@Value, char(10), '\n')	--换行
					SET @Value = replace(@Value, char(13), '\r')	--回车
					SET @Value = replace(@Value, char(8), '\b')	--退格
					SET @Value = replace(@Value, char(12), '\f') --换页
					--TODO: 增加其他JS控制符号?
				END
				
				--模板值@TemplateString替换为原值
				SET @Row =  replace(@Row, @TemplateString , '"' + @colname + '":"' + rtrim(ltrim(@Value)) + '",')
			END
			
		END
		FETCH NEXT from cur1 into @colname, @datatype  /*读取其它记录 */ 
	END  --一行处理完毕
    SET @JSON= @JSON + @Row + '},'
    SET @current_row = @current_row + 1
	SET @RowStart=CharIndex(@StartRoot,@XMLString,@RowEnd)
END
CLOSE cur1               
DEALLOCATE cur1 

	
IF LEN(@JSON)>0 SET @JSON=SubString(@JSON,0,LEN(@JSON))

--JQGRID READER FORMAT
--jsonReader :
--{
--	root: "rows",  //数据模型
--	page: "page",//数据页码
--	total: "total",//数据总页码
--	records: "records",//数据总记录数
--}

the_End:
SET @SQL = '"page":"' + convert(varchar(10), @page) + '",'
SET @SQL = @SQL + '"total":"' + convert(varchar(10), @total) + '",'
SET @SQL = @SQL + '"records":"' + convert(varchar(10), @rowcount) + '",'
SET @JSON = '"rows":[' + @JSON + ']'
SET @JSON = '{' + @SQL + @JSON + '}'

SET @JSON = REPLACE(@JSON, '",}', '"}')

SELECT @JSON AS json
END


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将SQL Server的任意记录转换为JSON格式(JQGRID) -- 支持SQL 2005 的相关文章

随机推荐

  • Epoll两种模式浅析(ET or LT)

    linux异步IO浅析 http hi baidu com kouu blog item e225f67b337841f42f73b341 html epoll有两种模式 Edge Triggered 简称ET 和 Level Trigge
  • 5GC自学-5G接入网组成

    5GC接入网 如图所示 xff1a EPC xff08 就是4G核心网 xff09 被分为New Core xff08 5GC xff0c 5G核心网 xff09 和MEC xff08 移动网络边界计算平台 xff09 两部分 MEC移动到
  • 《C++程序设计实验3》

    描述 晶晶的朋友贝贝约晶晶下周一起去看展览 xff0c 但晶晶每周的1 3 5必须上课 xff0c 请帮晶晶判断她能否接受贝贝的邀请 xff0c 如果能输出YES xff1b 如果不能则输出NO 输入 输入贝贝邀请晶晶去看展览的日期 xff
  • webpack--PWA(网站离线访问技术)

    webpack config js const WorkboxWebpackPlugin 61 require 39 workbox webpack plugin 39 终端下载npm i workbox webpack plugin D
  • Ubuntu安装wine的方法(Linux Ubuntu安装Windows软件)

    我打算完全从头开始 xff0c 写一个专门用于桌面办公的纯国产操作系统 xff0c 规避主流操作系统上影响用户体验的问题 xff0c 系统力求简洁 前言 xff1a wine可以让你在linux上运行一些常用的windows xff0c 如
  • 冒泡排序,并输出每一趟的排序结果

    span class token keyword public span span class token keyword static span span class token keyword void span span class
  • [Linux]基于select的Socket编程实现客户端群聊[非阻塞]

    先看效果 xff1a 客户端的代码 xff1a span class hljs comment Create by Gpwner 2017年1月5日21 30 16 span span class hljs preprocessor inc
  • 深入理解Nginx~用于调试进程和定位问题

    1 是否以守护进程方式运行Nginx 语法 xff1a daemon on off 默认 xff1a daemon on 守护进程 xff08 daemon xff09 是脱离终端并且在后台运行的进程 它脱离终端是为了避免进程执行过程中的信
  • 笔记本电脑坏了,那些零件可以再利用

    1 买个硬盘盒 xff0c 把笔记本硬盘改装成移动硬盘 2 把笔记本的屏幕拆下来 xff0c 上淘宝买改装用的套装 xff0c 可以把笔记本的屏幕改装成扩展显示器和电视 xff08 重点推荐 xff09 3 内存条拆下来 xff0c 留着以
  • 天气预报API接口大全

    国家气象局提供的天气预报接口 接口地址 xff1a http www weather com cn data sk 101010100 html http www weather com cn data cityinfo 101010100
  • VMware安装Debian完成,启动出现黑屏现象,仅有一个光标,以及给出解决办法

    VMware安装Debian完成 xff0c 启动出现黑屏现象 xff0c 仅有一个光标 xff0c 以及给出解决办法 一 启动黑屏问题二 解决办法 一 启动黑屏问题 VMware安装Debian过程中 xff0c 一路选择默认选项 xff
  • C语言对栈的操作

    span class hljs preprocessor include lt stdio h gt span span class hljs preprocessor include lt stdlib h gt span span cl
  • Godot实用代码1000例

    关于 这是 Godot实用代码1000例 的CSDN博客版本 xff08 之前是PPT版本 xff09 xff0c 将收录笔者自己探索和学习的一些简单Godot编程案例 文章目录 关于原版开篇的废话适合哪些人群建议前置知识 基础的移动 旋转
  • Godot官网新闻翻译 - 2015年

    本文是 Godot官网新闻翻译 系列的第1篇 xff0c 该系列旨在翻译和汇总Godot官网所发布的所有新闻 让更多英文不好的童鞋可以领悟官方新闻中的重要信息和真谛 官网新闻地址 xff1a https godotengine org ne
  • 一文简单了解并构建DockerFile

    GreatSQL社区原创内容未经授权不得随意使用 xff0c 转载请联系小编并注明来源 GreatSQL是MySQL的国产分支版本 xff0c 使用上与MySQL一致 作者 xff1a 蟹黄瓜子文章来源 xff1a GreatSQL社区投稿
  • 更新sudo apt source提示sources.list拼写错误的解决方法

    如果sudo apt uodate 更新失败 xff0c 多半是源的问题 xff0c 这是轻的症状 xff0c 根据提示 xff0c 把产生错误错误源去掉就行了 xff0c 但是情况较复杂怎么办 xff1f 如果有一天 xff0c 你在终端
  • 静态库和动态链接库的安装(Windows环境)

    库的安装 xff1a freeglut为例 1 在SourceForge下载freeglut库 xff0c 其中包括include src文件夹和CMakesLists txt freeglut download SourceForge n
  • C++ share_ptr 循环引用问题浅析

    share ptr指针涉及到循环引用问题会因为share ptr指针对应的use count 无法清0 xff0c 导致内存泄露 xff0c 直接上例子 xff1a class S B class S A public shared ptr
  • 树莓派raspberry pi更换国内镜像

    有时候使用sudo apt get 和pip install 安装软件和一些库的时候下载速度简直是龟速如下图 xff1a xff0c 是因为在系统默认状态下 xff0c 安装软件会选择从国外的服务器上下载软件 默认地址是http raspb
  • 将SQL Server的任意记录转换为JSON格式(JQGRID) -- 支持SQL 2005

    从SQL 2008开始 xff0c SQL Sever已经支持JSON数据 xff0c SQL 2016已经对JSON数据的处理支持非常完善 对于SQL 2016以上版本的用户 xff0c 可以直接调用原生方法 xff0c 效率更高 因客户