我需要帮助来微调我编写的代码。我是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,occup,phone_no,address)。在以下代码中,创建#table_result以匹配示例XML数据以便于演示。换句话说,表结构是已知的。因此我可以忽略XML数据中的字段名称,并专注于提取数据本身。
代码在SQL Server 2012上运行良好(您可以直接复制并粘贴运行代码),我可以得到如上所述。如果可能的话,我只需要对此进行微调。我有这样的行: - - 测试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
答案 0 :(得分:1)
这是 - 使用XML方法 - 多更容易!
试试这个:
DECLARE @xml XML='<table_result id="001" subj_cd="cdaaa" grade="b" name="Phua Chu Kang"/>';
SELECT One.Attr.value('fn:local-name(.)','varchar(max)') AS field
,One.Attr.value('.','varchar(max)') AS data
FROM @xml.nodes('table_result/@*') AS One(Attr)
结果
field data
id 001
subj_cd cdaaa
grade b
name Phua Chu Kang
现在我尝试模仿你的表结构(我建议从一开始就将数据存储为XML!在这种情况下,你可以省略第一个CROSS APPLY
和CAST ... AS XML
):
DECLARE @tbl TABLE(name VARCHAR(10),data VARCHAR(MAX));
INSERT INTO @tbl VALUES
('a','<table_result id="001" subj_cd="cdaaa" grade="b" name="Phua Chu Kang"/>')
,('b','<Another test="test data" test2="test2 data"/>')
,('c','<OneMore x="x data" y="y data" z="z data"/>');
SELECT tbl.name
,One.Attr.value('fn:local-name(..)','varchar(max)') AS element
,One.Attr.value('fn:local-name(.)','varchar(max)') AS field
,One.Attr.value('.','varchar(max)') AS data
FROM @tbl AS tbl
CROSS APPLY(SELECT CAST(tbl.data AS XML)) AS MyData(AsXml)
CROSS APPLY MyData.AsXml.nodes('*/@*') AS One(Attr)
结果
name element field data
a table_result id 001
a table_result subj_cd cdaaa
a table_result grade b
a table_result name Phua Chu Kang
b Another test test data
b Another test2 test2 data
c OneMore x x data
c OneMore y y data
c OneMore z z data
答案 1 :(得分:0)
现在,我对T-SQL XML并不是很了解,但你不能这样做:
app:layout_scrollFlags="scroll|enterAlways"
请注意,我将create table #dummy (name nvarchar(max), data xml);
insert into #dummy
values ('a', '<table_result id="001" subj_cd="cdaaa" grade="b" name="phua chu kang"/>');
select 'id' "field",
elem.value('@id', 'nvarchar(50)') "data"
from #dummy
cross apply data.nodes('/table_result') tbl(elem)
union all
select 'subj_cd' "field",
elem.value('@subj_cd', 'nvarchar(50)') "data"
from #dummy
cross apply data.nodes('/table_result') tbl(elem)
union all
select 'grade' "field",
elem.value('@grade', 'nvarchar(50)') "data"
from #dummy
cross apply data.nodes('/table_result') tbl(elem)
union all
select 'name' "field",
elem.value('@name', 'nvarchar(50)') "data"
from #dummy
cross apply data.nodes('/table_result') tbl(elem);
的数据类型更改为#dummy.data
。这需要能够使用XML函数。