从子节点openxml sql返回相同的节点值

时间:2017-08-05 08:45:05

标签: sql-server stored-procedures sql-server-2012 sql-server-openxml

我有以下XML: -

<XML>
<ProductDetail>
   <ProductId>1</ProductId>
   <PropertyDetail>
      <PropertyKey>Size</PropertyKey>
      <PropertyValue>XXL</PropertyValue>
      <PropertyKey>ProdTaxType</PropertyKey>
      <PropertyValue>5%</PropertyValue>
      <PropertyKey>Incl/Excl</PropertyKey>
      <PropertyValue>True</PropertyValue>        
      <PropertyKey>Fit</PropertyKey>
      <PropertyValue>SLIM F/S</PropertyValue>
   </PropertyDetail>
</ProductDetail>
</XML>

但是,我得到的结果如下:

ProductId   PropertyKey PropertyValue
   1           Size        XXL

我需要使用openxml获取所有PropertyDetail。我在MS SQL 2012中的存储过程中的小查询如下:

SELECT XML.ProductId, XML.PropertyKey, XML.PropertyValue FROM 
   OPENXML (@hDoc, '/XML/*', 2) WITH (
      ProductId INT 'ProductId',
      PropertyKey VARCHAR(200) 'PropertyDetail/PropertyKey',
      PropertyValue VARCHAR(200) 'PropertyDetail/PropertyValue'
   ) XML

finall结果如下所示:

ProductId   PropertyKey   PropertyValue
   1           Size          XXL
   1         ProdTaxType     5%
   1         Incl/Excl      True
   1           Fit         SLIM F/S    

1 个答案:

答案 0 :(得分:1)

我会尝试以下解决方案:

DECLARE @x XML = N'<XML>
<ProductDetail>
   <ProductId>1</ProductId>
   <PropertyDetail>
      <PropertyKey>Size</PropertyKey>
      <PropertyValue>XXL</PropertyValue>
      <PropertyKey>ProdTaxType</PropertyKey>
      <PropertyValue>5%</PropertyValue>
      <PropertyKey>Incl/Excl</PropertyKey>
      <PropertyValue>True</PropertyValue>        
      <PropertyKey>Fit</PropertyKey>
      <PropertyValue>SLIM F/S</PropertyValue>
   </PropertyDetail>
</ProductDetail>
</XML>'

SELECT pvt.ProductId, pvt.NodeNum, pvt.[0] AS PKey, pvt.[1] AS PValue
FROM (
    SELECT  x.XmlCol.value('(ProductId/text())[1]', 'INT')          AS ProductId,
            (DENSE_RANK() OVER(ORDER BY y.XmlCol) + 1)/2            AS NodeNum,
            (DENSE_RANK() OVER(ORDER BY y.XmlCol) + 1) % 2          AS NodeType, -- 0 = PropertyKey, 1 = PropertyValue
            y.XmlCol.value('(text())[1]', 'NVARCHAR(50)')           AS NodeValue
    FROM    @x.nodes('XML/ProductDetail') x(XmlCol)
    OUTER APPLY x.XmlCol.nodes('PropertyDetail/*') y(XmlCol)
) AS src -- source
PIVOT( MAX(src.NodeValue) FOR NodeType IN ([0], [1]) ) AS pvt

结果:

ProductId NodeNum PKey        PValue
--------- ------- ----------- --------
1         1       Size        XXL
1         2       ProdTaxType 5%
1         3       Incl/Excl   True
1         4       Fit         SLIM F/S

参考:Uniquely Identifying XML Nodes with DENSE_RANK

Online Demo

注意:我不知道是否可能,但我会更改XML架构:

...
<property name="Size" value="XXL" />
<property name="ProdTaxType" value="5%" />
...

实际的XML架构在某种程度上是危险的,因为它依赖于PropertyKey / PropertyValue XML元素的顺序。