gpt4 book ai didi

sql - 改进 SQL Server 查询以将任意表转换为 JSON

转载 作者:行者123 更新时间:2023-12-03 16:55:26 27 4
gpt4 key购买 nike

在使用网络上的 FOR XML 和 .nodes() 命令进行大量搜索和拼凑用于转换结果集的非常出色的技术之后,我能够创建这个单一的查询(不是存储过程),它可以合理地将任何任意 SQL 查询转换为 JSON 数组的工作做得很好。

查询会将每个数据行编码为一个带有前导逗号的 JSON 对象。
数据行用括号括起来,然后整个结果集应该导出到一个文件中。

我想看看是否有人可以看到提高其性能的方法?

这是带有示例表的查询:

declare @xd table (col1 varchar(max), col2 int, col3 real, colNull int) 

insert into @xd
select '', null, null, null
UNION ALL select 'ItemA', 123, 123.123, null
UNION ALL select 'ItemB', 456, 456.456, null
UNION ALL select '7890', 789, 789.789, null

select '[{}'
UNION ALL
select ',{' + STUFF((
(select ','
+ '"' + r.value('local-name(.)', 'varchar(max)') + '":'
+ case when r.value('./@xsi:nil', 'varchar(max)') = 'true' then 'null'
when isnumeric(r.value('.', 'varchar(max)')) = 1
then r.value('.', 'varchar(max)')
else '"' + r.value('.', 'varchar(max)') + '"'
end
from rows.nodes('/row/*') as x(r) for xml path(''))
), 1, 1, '') + '}'
from (
-- Arbitrary query goes here, (fields go where t.* is, table where @xd t is)
select (select t.* for xml raw,type,elements XSINIL) rows
from @xd t
) xd
UNION ALL
select ']'

我对它最大的批评是它非常慢。
目前,大约 42,000 行大约需要 3:30。

我的另一个重要批评是它目前假设所有看起来像数字的东西都是数字。它至少不会尝试发现列类型(我什至不确定它是否可以)。

最后一个小批评是第一个数据行前面会有一个逗号,技术上不应该。为了弥补这一点,它需要在开始 JSON 数组的第一行中使用空的 JSON 对象。

邀请了其他批评(最好是解决方案),我唯一真正的限制是该解决方案在许多任意 SQL 查询上都可以很好地重复,而无需明确标识列名。

我正在使用 SQL Server 2012。

感谢和我一样正在寻找通用 SQL 结果 -> JSON 数组转换器的其他人,享受吧!

最佳答案

我说如果你真的想提高性能,就使用元编程。下面的示例尝试使用 40,000 行并在不到一秒的时间内返回结果(不包括插入最初的 40k 行,在此示例中只需要大约 2 秒)。它还考虑了您的数据类型,不要将数字括在引号中。

declare @xd table (col1 varchar(max), col2 int, col3 real, colDate datetime, colNull int);

declare @i int = 0;

while @i < 10000 begin
set @i += 1;
insert into @xd
select '', null, null, null, null
union all select 'ItemA', 123, 123.123, getDate(), null
union all select 'ItemB', 456, 456.456, getDate(), null
union all select '7890', 789, 789.789, getDate(), null;
end;

select *
into #json_base
from (
-- Insert SQL Statement here
select * from @xd
) t;

declare @columns table (
id int identity primary key,
name sysname,
datatype sysname,
is_number bit,
is_date bit);

insert into @columns(name, datatype, is_number, is_date)
select columns.name, types.name,
case when number_types.name is not NULL
then 1 else 0
end as is_number,
case when date_types.name is not NULL
then 1 else 0
end as is_date
from tempdb.sys.columns
join tempdb.sys.types
on (columns.system_type_id = types.system_type_id)
left join (values ('int'), ('real'), ('numeric'),
('decimal'), ('bigint'), ('tinyint')) as number_types(name)
on (types.name = number_types.name)
left join (values ('date'), ('datetime'), ('datetime2'),
('smalldatetime'), ('time'), ('datetimeoffset')) as date_types(name)
on (types.name = date_types.name)
where object_id = OBJECT_ID('tempdb..#json_base');

declare @field_list varchar(max) = STUFF((
select '+'',''+' + QUOTENAME(QUOTENAME(name, '"') + ':', '''')
+ '+' + case when is_number = 1
then 'COALESCE(LTRIM('
+ QUOTENAME(name) + '),''null'')'
when is_date = 1
then 'COALESCE(QUOTENAME(LTRIM(convert(varchar(max), '
+ QUOTENAME(name) + ', 126)),''"''),''null'')'
else 'COALESCE(QUOTENAME('
+ QUOTENAME(name) + ',''"''),''null'')'
end
from @columns
for xml path('')),
1, 5, '');

create table #json_result (
id int identity primary key,
line varchar(max));

declare @sql varchar(max) = REPLACE(
'insert into #json_result '
+ 'select '',{''+{f}+''}'' '
+ 'from #json_base', '{f}', @field_list);

exec(@sql);

update #json_result
set line = STUFF(line, 1, 1, '')
where id = 1;

select '['
UNION ALL
select line
from #json_result
UNION ALL
select ']';

drop table #json_base;
drop table #json_result;

关于sql - 改进 SQL Server 查询以将任意表转换为 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14865199/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com