在xml列中搜索多个值

时间:2012-09-09 20:39:48

标签: sql xml xquery-sql

环境: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

如何优化?

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