环境:SQL Server 2012.主要和次要(值)索引构建在xml列上。
假设我有一个包含xml列WordIndex的表消息。我还有一个表Word,其中包含WordId和WordText。 Message.WordIndex的Xml具有以下模式:
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.com">
<xs:element name="wi">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="w">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="p" type="xs:unsignedByte" />
</xs:sequence>
<xs:attribute name="wid" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
和一些数据:
<wi xmlns="http://www.example.com">
<w wid="1">
<p>28</p>
<p>72</p>
<p>125</p>
</w>
<w wid="4">
<p>89</p>
</w>
<w wid="5">
<p>11</p>
</w>
</wi>
我需要使用OR或AND在xml列WordIndex中搜索多个值。我正在做的事情相当简陋,因为我是XQuery中的n00b(取自调试输出,因此是实际值):
with xmlnamespaces(default 'http://www.example.com')
select
m.Subject,
m.MessageId,
m.WordIndex.query('
let $dummy := 0
return
<word_list>
{
for $w in /wi/w
where $w/@wid=64
return <word wid="64" pos="{data($w/p)}"/>
}
{
for $w in /wi/w
where $w/@wid=70
return <word wid="70" pos="{data($w/p)}"/>
}
{
for $w in /wi/w
where $w/@wid=63
return <word wid="63" pos="{data($w/p)}"/>
}
</word_list>
') as WordPosition
from
Message as m
-- more joins go here ...
where
-- more conditions go here ...
and m.WordIndex.exist('/wi/w[@wid=64]') = 1
and m.WordIndex.exist('/wi/w[@wid=70]') = 1
and m.WordIndex.exist('/wi/w[@wid=63]') = 1
如何优化?
答案 0 :(得分:0)
不确定我理解你的预期结果是什么,但是你可以使它更通用和数据驱动(例如使用sql:column或sql:variable)。尝试这样的事情:
declare @wids table ( wid INT PRIMARY KEY )
insert into @wids ( wid )
values ( 64 ), ( 70 )
;with xmlnamespaces(default 'http://www.example.com')
select
m.Subject,
m.MessageId,
m.WordIndex.query('
return
<word_list>
{
for $w in /wi/w
where $w/@wid = sql:column("w.wid")
return <word wid="{$w/@wid}" pos="{data($w/p)}"/>
}
</word_list>
') as WordPosition
from
Message as m
cross apply @wids w
where m.WordIndex.exist('wi/w[@wid=sql:column("w.wid")]') = 1