Подтвердить что ты не робот

XQuery [value()]: 'value()' требует одиночного (или пустой последовательности), найденного операнда типа 'xdt: untypedAtomic *'

Я пытаюсь вставить строки в таблицу, используя выбор из XML. Я думаю, что я рядом. Где я ошибаюсь?

declare @xmldata xml;
set @xmldata = '<Database>
                  <PurchaseDetails>
                    <PurchaseDetail>
                      <Upc>72594206916</Upc>
                      <Quantity>77</Quantity>
                      <PurchaseDate>9/2010</PurchaseDate>
                      <PurchaseCity>Dallas</PurchaseCity>
                      <PurchaseState>TX</PurchaseState>
                    </PurchaseDetail>
                    <PurchaseDetail>
                      <Upc>72594221854</Upc>
                      <Quantity>33</Quantity>
                      <PurchaseDate>12/2013</PurchaseDate>
                      <PurchaseCity>Nashville</PurchaseCity>
                      <PurchaseState>TN</PurchaseState>
                    </PurchaseDetail>
                  </PurchaseDetails>
                </Database>'

insert into PurchaseDetails
(Upc, Quantity, PurchaseDate, PurchaseCity, PurchaseState)
select
    x.Rec.value('Upc','char(11)'),
    x.Rec.value('Quantity','int'),
    x.Rec.value('PurchaseDate','varchar(7)'),
    x.Rec.value('PurchaseCity','varchar(50)'),
    x.Rec.value('PurchaseState','char(2)')
from @xmlData.nodes('//Database/PurchaseDetails/PurchaseDetail') as x(Rec)
4b9b3361

Ответ 1

Сотрудник столкнулся с аналогичной проблемой раньше. Вот что мы придумали. НЕ интуитивно!
insert into PurchaseDetails
(Upc, Quantity, PurchaseDate, PurchaseCity, PurchaseState)
select
    pd.value('Upc[1]','char(11)'),
    pd.value('Quantity[1]','int'),
    pd.value('PurchaseDate[1]','varchar(7)'),
    pd.value('PurchaseCity[1]','varchar(50)'),
    pd.value('PurchaseState[1]','char(2)')
from @xmlData.nodes('//Database/PurchaseDetails') as x(Rec)
cross apply @xmlData.nodes('//Database/PurchaseDetails/PurchaseDetail') as i(pd)

Ответ 2

insert into PurchaseDetails(Upc, Quantity, PurchaseDate, PurchaseCity, PurchaseState)
select T.X.value('(Upc/text())[1]', 'char(11)'),
       T.X.value('(Quantity/text())[1]', 'int'),
       T.X.value('(PurchaseDate/text())[1]', 'varchar(7)'),
       T.X.value('(PurchaseCity/text())[1]', 'varchar(50)'),
       T.X.value('(PurchaseState/text())[1]', 'char(2)')
from @xmlData.nodes('/Database/PurchaseDetails/PurchaseDetail') as T(X)

Ответ 3

Попробуйте это! query() then value()
запустите это в SQL Server и выполните 100% поместите точку (.) сначала, затем дочерний тег.
Тег PurchaseDetail существует 2 раза, поэтому точка (.) Заменяет первый и второй теги.
Точка может предотвратить использование [1] на XQuery.
Точка представляет первый и второй теги BuyDetail.

INSERT INTO PurchaseDetails(Upc, Quantity, PurchaseDate, PurchaseCity, PurchaseState)
SELECT col.query('./Upc').value('.', 'char(11)'),
    col.query('./Quantity').value('.', 'int'),
    col.query('./PurchaseDate').value('.', 'varchar(7)'),
    col.query('./PurchaseCity').value('.', 'varchar(50)'),
    col.query('./PurchaseState').value('.', 'char(2)')
FROM @xmlData.nodes('/Database/PurchaseDetails/PurchaseDetail') as ref(col)

Это более упрощенный запрос.
Посмотрите, работает ли он

Ответ 4

select
    x.Rec.query('./Upc').value('.','char(11)')
    ,x.Rec.query('./Quantity').value('.','int')
    ,x.Rec.query('./PurchaseDate').value('.','varchar(7)')
    ,x.Rec.query('./PurchaseCity').value('.','varchar(50)')
    ,x.Rec.query('./PurchaseState').value('.','char(2)')
from @xmlData.nodes('/Database/PurchaseDetails/PurchaseDetail') as x(Rec)

Ответ 5

Борется с подобной проблемой и обнаружил, что ответ @birdus не сработал, если у вас есть дополнительные слои вложения в xml, на которые вы ссылались в своем XQuery, например, Предположим, немного отличную форму XML, если у вас есть

T.x.value('PurchasePlace/PurchaseCity[1]','varchar(50)')

вы все равно получите ошибку синглтона. Хотя решение @birdus подходит для этого конкретного случая, более универсальное решение, сочетающее в себе лучшее из @birdus & Решение @Mikael-Eriksson заключается в следующем:

insert into PurchaseDetails(Upc, Quantity, PurchaseDate, PurchaseCity, PurchaseState)
select T.X.value('(Upc)[1]', 'char(11)'),
T.X.value('(Quantity)[1]', 'int'),
T.X.value('(PurchaseDate)[1]', 'varchar(7)'),
T.X.value('(PurchaseCity)[1]', 'varchar(50)'),
T.X.value('(PurchaseState)[1]', 'char(2)')
from @xmlData.nodes('/Database/PurchaseDetails/PurchaseDetail') as T(X)

Это объединяет @birdus пропуск /text(), который является излишним, но добавляет круглые скобки @Mikael-Eriksson вокруг селектора элемента, чтобы разрешить несколько селекторов элемента, как в моем модифицированном примере, который становится:

T.x.value('(PurchasePlace/PurchaseCity)[1]','varchar(50)')

Причина этого, о которой некоторые спрашивали, заключается не в том, что версия @birdus возвращает что-либо, кроме синглтона в любом из рассмотренных здесь примеров, а в том, что это возможно. В Документах Microsoft:

Шаги расположения, параметры функции и операторы, которые требуют синглетонов, вернут ошибку, если компилятор не сможет определить, гарантирован ли синглтон во время выполнения.

Ответ 6

Чтобы решить вопрос о том, почему требуется позиционный предикат (т.е. [1]) в строковом литерале XQuery, как указано в @pbz, требуется синглтон, и поэтому он должен быть гарантирован. Чтобы добавить больше вещества в ответ @pbz, см. ниже.

По Microsoft Документы SQL:

  В следующем примере экземпляр XML хранится в переменной типа xml. Метод value() извлекает значение атрибута ProductID   из XML. Затем значение присваивается переменной int.

DECLARE @myDoc xml  
DECLARE @ProdID int  
SET @myDoc = '<Root>  
<ProductDescription ProductID="1" ProductName="Road Bike">  
<Features>  
  <Warranty>1 year parts and labor</Warranty>  
  <Maintenance>3 year parts and labor extended maintenance is available</Maintenance>  
</Features>  
</ProductDescription>  
</Root>'  

SET @ProdID =  @myDoc.value('(/Root/ProductDescription/@ProductID)[1]', 'int' )  
SELECT @ProdID  

В результате возвращается значение 1.

Хотя в экземпляре XML есть только один атрибут ProductID, правила статической типизации требуют, чтобы вы явно указали, что выражение пути возвращает одиночный тег. Поэтому дополнительный [1] указывается в конце выражения пути. Для дополнительной информации о статической типизации см. XQuery и статическая типизация.

Переход по этой ссылке приводит нас к:

Как упоминалось ранее, вывод типа часто выводит тип, который шире, чем то, что пользователь знает о типе данных, которые проходить В этих случаях пользователь должен переписать запрос. Несколько Типичные случаи включают в себя следующее:

...

  • Тип указывает на большую мощность, чем то, что на самом деле содержат данные. Это часто происходит, потому что тип данных XML может
    содержит более одного элемента верхнего уровня
    и коллекцию XML-схем не может сдержать это. Чтобы уменьшить статический тип и
    гарантируя, что действительно передается не более одного значения, вы
    должен использовать позиционный предикат [1]. Например, чтобы добавить 1 к значение атрибута c элемента b под верхним уровнем a
    элемент, вы должны написать (/a/b/@c)[1]+1. Дополнительно ДОКУМЕНТ
    Ключевое слово может использоваться вместе с коллекцией XML-схем.