【发布时间】:2016-02-03 18:26:11
【问题描述】:
我需要帮助来微调我编写的这段代码。我是 SQL Server 的新手,我相信有更好的方法可以做到这一点,或者也许可以简化或微调以下代码以提高性能或节省内存资源。
基本上,我有这个 XML 数据:
<table_result id="001" subj_cd="cdaaa" grade="b" name="Phua Chu Kang"/>
我想根据 XML 数据创建一个如下所示的表
请注意以下几点:
-
SplitThis不是内置函数(检查下面的代码)。
数据可以有空格,但由" 分隔。另请注意,对于该特定给定表,XML 数据可以具有不同数量的字段-数据对 - 在以下代码中称为 #dummy。即上面的示例 XML 数据有 4 个字段(id、subj_cd、grade、name),下一个 XML 数据可能有 5 个字段(即 id、name、职业、phone_no、地址)。在以下代码中,创建了#table_result 以匹配示例 XML 数据以便于演示。换句话说,表结构是已知的。所以我可以忽略 XML 数据中的字段名称,而专注于提取数据本身。
该代码在 SQL Server 2012 上运行良好(您可以直接复制粘贴运行代码),我能够如上所示。如果可能的话,我只需要微调它。我有这样的行: - - test blabla。您可以取消注释并尝试。我可以使用增强功能,例如避免使用临时表的数量或以任何方式替换代码中 row_number() 的使用。
/* remove all temp tables */
declare @sql varchar(5000)
SELECT @sql = isnull(@sql+';', '') + 'drop table ' + SUBSTRING(t.name, 1, CHARINDEX('___', t.name)-1)
FROM tempdb..sysobjects AS t
WHERE t.name LIKE '#%[_][_][_]%'
AND t.id =OBJECT_ID('tempdb..' + SUBSTRING(t.name, 1, CHARINDEX('___', t.name)-1));
exec (@sql)
/* end */
/* function */
drop function splitthis
go
create function splitthis(@separator char(1), @list varchar(max))
returns @returntable table(item nvarchar(max))
as
begin
declare @index int
declare @newtext varchar(max)
if @list = null
return
set @index = charindex(@separator, @list)
while not(@index = 0)
begin
set @newtext = rtrim(ltrim(left(@list, @index - 1)))
set @list = right(@list, len(@list) - @index)
insert into @returntable(item) values(@newtext)
set @index = charindex(@separator, @list)
end
insert into @returntable(item) values(rtrim(ltrim(@list)))
update @returntable set item='' where item is null
return
end
go
/* end of function */
/* create dummy tables */
create table #table_result
(id nvarchar(max), subj_cd nvarchar(max), grade nvarchar(max), name nvarchar(max))
create table #dummy (name nvarchar(max), data nvarchar(max))
insert into #dummy
values ('a', '<table_result id="001" subj_cd="cdaaa" grade="b" name="phua chu kang"/>');
--test : select * from #dummy
/* remove the fist non-data opening tag */
declare @record nvarchar(max)
select @record = data from #dummy where name = 'a'
select *, null as temp into #tempb from splitthis(' ',@record)
select *, row_number() over (order by temp) count into #tempc from #tempb
select item into #tempd from #tempc where #tempc.count>1
-- test : select * from #tempd
/* get the actual field & data into a single column table */
declare @temp varchar(max)
set @temp=''select @temp=@temp+' ' + item from #tempd
select *, null as temp into #tempe from splitthis('"',@temp)
select *, row_number() over (order by temp) count into #tempf from #tempe
select item, count into #tempg from #tempf
--test : select * from #tempg
/* prepare the data table */
select
case when #tempg.count % 2 = 0
then item
else null
end as data
into #temph
from #tempg
select data, null as temp into #tempi from #temph
select data, row_number() over (order by temp) count into #data from #tempi
where data is not null
--test : select * from #data
/* prepare the field table. */
select name, null as temp into #tempj
from tempdb.sys.columns where object_id=object_id('tempdb..#table_result');
select *, row_number() over (order by temp) count into #field from #tempj
--test : select * from #field
/* get the final table */
select a.name as field, b.data from #field a
left join #data b on a.count=b.count
【问题讨论】:
-
您发布的拆分器绝对是所有可用拆分器中性能最差的,遗憾的是它也是最常见的。有关性能要好得多的几种替代方案,请参阅本文。 sqlperformance.com/2012/07/t-sql-queries/split-strings
-
我想这可能会对你有所帮助Convert Xml to Table SQL Server
-
我想,这是XY-Problem。您不需要拆分代码的帮助,但实际上需要另一种方法。如果我没有弄错您的问题,那么问题是:我如何才能将属性及其值作为一般 XML-Element 的名称-值对来获取?
-
是的,另一种方法也很棒。下面发布的答案很好
标签: sql-server xml