#sql #sql-server #xml #xquery-sql
#sql #sql-сервер #xml #xquery-sql
Вопрос:
У меня простой XML:
DECLARE @x1 xml = '<r>
<o a="1">
<o a="2">
</o>
</o>
</r>';
И выберите следующее:
SELECT r.o.value('(../@a)[1]','varchar(20)') FROM @x1.nodes('/r//o') r(o);
Все хорошо:
NULL
1
Когда я использую типизированный XML:
CREATE XML SCHEMA COLLECTION [dbo].test AS '
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="r">
<xsd:complexType>
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="o" type="o" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="o">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="o" type="o" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="a" type="xsd:string" />
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>'
GO
DECLARE @x2 xml(dbo.test) = '<r>
<o a="1">
<o a="2">
</o>
</o>
</r>';
SELECT r.o.value('(../@a)[1]','varchar(20)') FROM @x2.nodes('/r//o') r(o);
Я получил ошибку:
XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
Почему нетипизированный XML работает, а типизированный XML — нет?
Комментарии:
1. StackOverflow всегда возражал против таких вещей, как короткие вопросы и краткие ответы, требуя, чтобы вы заполняли их мусором, чтобы удовлетворить его проверку правил. Похоже, ситуация ухудшается. Просто продолжайте добавлять дополнения и надейтесь, что они улучшат правила.
Ответ №1:
Похоже, вы хорошо понимаете, что это не обычная проблема, связанная с необходимостью убедить анализатор в том, что передается только одна вещь value()
. Как вы заметили, эта проблема специфична для typed XML.
Используя Google, я нашел этот древний пост в блоге с многообещающим текстом
rt является частью модели данных XQuery 1.0 / XPath 2.0.
Большинство людей справляются с этим. Настоящее веселье начинается, когда вы выполняете примеры с использованием нетипизированных выражений XML и XPath с помощью теста узла text(). text () отлично работает при использовании нетипизированного XML, но не работает с типизированным XML с простым содержимым
В нем говорится об онлайн-книгах по SQL и документе с рекомендациями по SQL Server 2005 XML, который, думаю, является этой книгой. Я не искал более актуальную ссылку. Но, используя то, что я там нашел, я смог решить вашу проблему: простая замена
SELECT r.o.value('(../@a)[1]','varchar(20)') FROM @x2.nodes('/r//o') r(o);
с
SELECT r.o.value('fn:string(../@a)[1]','varchar(20)') FROM @x2.nodes('/r//o') r(o);
В принципе, value()
не нравится, когда ему присваиваются значения типа typed-xml, но ему нужны строки. Итак, мы присваиваем ему строку.