XQuery [value()]:'value()'需要单例(或空序列),找到类型为'xdt:untypedAtomic *'的操作数

时间:2013-11-12 21:46:53

标签: xml tsql xpath

我正在尝试使用select from 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)

6 个答案:

答案 0 :(得分:45)

一位同事之前曾解决过类似的问题。这就是我们想出的。不直观!

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)

答案 1 :(得分:17)

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)

答案 2 :(得分:16)

试试这个!
query()then value()
在SQL Server中运行它并且100%工作了 首先放一个点(。)然后放入子标签 PurchaseDetail标签存在2次,因此点(。)替换第一个和第二个标签 点可以防止在XQuery上使用[1] 点代表第一个和第二个PurchaseDetail标签。

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)

到目前为止,这是更简化的查询 看看它是否有效

答案 3 :(得分:13)

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)

答案 4 :(得分:4)

遇到类似的问题,发现如果你在xml中有你在XQuery中引用的额外的嵌套层,@ birdus的答案是行不通的,例如:假设有一个稍微不同的XML形状,如果你有

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

你仍会得到单身人士的错误。虽然@ birdus的解决方案确实适用于这个特定情况,但是更为普遍适用的解决方案结合了@ birdus&amp; amp; s&amp; @ 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的版本在这里讨论的任何一个例子中都返回了除单身之外的东西,但它< EM>可能。每Microsoft Docs

  

如果编译器无法确定在运行时是否保证单例,则需要单例的位置步骤,函数参数和运算符将返回错误。

答案 5 :(得分:1)

要解决为什么的问题,需要XQuery字符串文字中的位置谓词(即[1])(如指示的@pbz),因此需要一个单例,因此必须保证。要在@pbz的答案中添加更多内容,请参见下文。

根据Microsoft的SQL Docs

  
    

在以下示例中,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 and Static Typing

点击该链接,我们将转到:

  

如前所述,类型推断经常推断类型为   比用户所了解的数据类型更广泛   被通过。在这种情况下,用户必须重写查询。   典型的情况如下:

     

...

     
      
  • 类型比数据实际包含的基数更高这经常发生,因为 xml数据类型可以
      包含多个顶级元素
    和一个XML模式集合   不能限制这一点。为了减少静态类型和
      确保您确实传递了最多一个价值,您
      应该使用位置谓词[1]
    。例如,将1加到   顶级a下元素b的属性c的值
      元素,您必须写(/a/b/@c)[1]+1。此外,DOCUMENT
      关键字可以与XML模式集合一起使用。
  •