用于解释模式定义的XQuery语法

时间:2012-09-09 15:52:04

标签: sql xml xquery-sql

环境:SQL Server 2012。

假设我有一个包含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>

我还使用XQuery代码进行SQL查询,如下所示:

with WordIds as
(
    select distinct
        t.c.value('@wid', 'int') as XmlWordId
    from
        Message as m
        cross apply
            m.WordIndex.nodes('/wi/w') as t(c)
    inner join Word as w
        on w.WordId = t.c.value('@wid', 'int')

-- some more joins go here ...
)
select
    count(*)
from
    WordIds

和这个(这个不起作用,因为我开始在其中引入模式):

with xmlnamespaces('http://www.example.com' as ns)
select
    wi.Position,
    w.WordId,
    w.WordText
from
(
    select
        t.c.value('.', 'int') as Position,
        t.c.value('../@wid', 'int') as WordId
    from
        Message as m
        cross apply m.WordIndex.nodes('//p') as t(c)
    where
        m.MessageId = @MessageId
) as wi
inner join Word as w
    on w.WordId = wi.WordId
order by
    wi.Position

问题:

限定参数以调用.value()和.nodes()的正确语法是什么? 我得到的错误是我不完全理解的:

XQuery [Message.WordIndex.value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:anyAtomicType *'

2 个答案:

答案 0 :(得分:2)

尝试以下查询:

;with xmlnamespaces( default 'http://www.example.com'), WordIds as 
( 
    select distinct 
        t.c.value('@wid', 'int') as XmlWordId 
    from 
        Message as m 
        cross apply 
            m.WordIndex.nodes('/wi/w') as t(c) 
    inner join Word as w 
        on w.WordId = t.c.value('@wid', 'int') 

-- some more joins go here ... 
) 
select 
    count(*) 
from 
    WordIds 


;with xmlnamespaces( default 'http://www.example.com')
select 
    w.c.value('@wid', 'INT') wid,
    p.c.value('.', 'INT') p
from message m
    cross apply m.wordIndex.nodes('wi/w') w(c)
        cross apply w.c.nodes('p') p(c)

通常,请尝试避免使用父轴(..),因为它存在性能问题。而是使用多个CROSS APPLY向下钻取到xml从左到右。

有关命名空间的更多信息,请查看本文:

使用WITH XMLNAMESPACES添加命名空间

http://msdn.microsoft.com/en-us/library/ms177400.aspx

答案 1 :(得分:1)

这只是一个句法规则,引自:

http://msdn.microsoft.com/en-us/library/ms175972.aspx

“当CTE在作为批处理一部分的语句中使用时,其前面的语句必须后跟分号。”