我有一个包含如下元素的 XML 列:
<Root>
<Word Type="pre1" Value="A" />
<Word Type="pre1" Value="D" />
<Word Type="base" Value="B" />
<Word Type="post1" Value="C" />
<Word Type="post1" Value="E" />
<Word Type="post1" Value="F" />
</Root>
那个模型是这样的:
并希望在 MSSQL 中使用 XQuery 选择所有可能的路径以获得类似这样的结果:
ABC ABE ABF DBC DBE DBF
或者类似的东西:
<Root>
<Word Type="pre1" Value="A" />
<Word Type="pre1" Value="D" />
<Word Type="pre2" Value="G" />
<Word Type="pre2" Value="H" />
<Word Type="base" Value="B" />
<Word Type="post1" Value="C" />
<Word Type="post1" Value="E" />
<Word Type="post1" Value="F" />
</Root>
结果是:
AHBC AHBE AHBF DHBC DHBE DHBF AGBC AGBE AGBF DGBC DGBE DGBF
最佳答案
您可以使用 CTE 构建唯一类型列表,然后在递归 CTE 中使用它来构建字符串。最后,您挑选出上次迭代中生成的字符串。
with Types as
(
select row_number() over(order by T.N) as ID,
T.N.value('.', 'varchar(10)') as Type
from (select @XML.query('for $t in distinct-values(/Root/Word/@Type)
return <T>{$t}</T>')
) as X(T)
cross apply X.T.nodes('/T') as T(N)
),
Recu as
(
select T.Type,
T.ID,
X.N.value('@Value', 'varchar(max)') as Value
from Types as T
cross apply @XML.nodes('/Root/Word[@Type=sql:column("T.Type")]') as X(N)
where T.ID = 1
union all
select T.Type,
T.ID,
R.Value+X.N.value('@Value', 'varchar(max)') as Value
from Types as T
inner join Recu as R
on T.ID = R.ID + 1
cross apply @XML.nodes('/Root/Word[@Type=sql:column("T.Type")]') as X(N)
)
select R.Value
from Recu as R
where R.ID = (select max(T.ID) from Types as T)
order by R.Value
更新
这是一个性能更好的版本。它将 XML 分解为两个临时表。每种类型一个,所有单词一个。仍然需要递归 CTE,但它使用表而不是 XML。 CTE 中的连接使用的每个临时表上还有一个索引。
-- Table to hold all values
create table #Values
(
Type varchar(10),
Value varchar(10)
);
-- Clustered index on Type is used in the CTE
create clustered index IX_#Values_Type on #Values(Type)
insert into #Values(Type, Value)
select T.N.value('@Type', 'varchar(10)'),
T.N.value('@Value', 'varchar(10)')
from @XML.nodes('/Root/Word') as T(N);
-- Table that holds one row for each Type
create table #Types
(
ID int identity,
Type varchar(10),
primary key (ID)
);
-- Add types by document order
-- Table-Valued Function Showplan Operator for nodes guarantees document order
insert into #Types(Type)
select T.Type
from (
select row_number() over(order by T.N) as rn,
T.N.value('@Type', 'varchar(10)') as Type
from @XML.nodes('/Root/Word') as T(N)
) as T
group by T.Type
order by min(T.rn);
-- Last level of types
declare @MaxID int;
set @MaxID = (select max(ID) from #Types);
-- Recursive CTE that builds the strings
with C as
(
select T.ID,
T.Type,
cast(V.Value as varchar(max)) as Value
from #Types as T
inner join #Values as V
on T.Type = V.Type
where T.ID = 1
union all
select T.ID,
T.Type,
C.Value + V.Value
from #Types as T
inner join C
on T.ID = C.ID + 1
inner join #Values as V
on T.Type = V.Type
)
select C.Value
from C
where C.ID = @MaxID
order by C.Value;
-- Cleanup
drop table #Types;
drop table #Values;
关于sql - 从具有图形内容的 Xml 中选择所有路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16185977/