用于将xml传递到数据库的SQL查询

时间:2016-01-20 20:28:41

标签: sql sql-server xml

我有一个我试图解析成数据库表的Xml文件。

我有一些代码可以做到这一点..但它没有适当地将代码组织到表中,因为它返回所有产品和房间而没有任何订单。

从下面可以看到,xml首先定义房间名称和RoomId。

接下来是该房间的产品清单。 这些产品都存储在表格中,并已分配父级和子级ID。

然后,XML为不同的房间重复此结构。

我已经采用了一些代码,因为有很多样式和不必要的代码。

我想要的是一个可以正确存储此数据的查询,以便我可以将其存储在数据库中,然后在“SQL Server报告”构建器中检索它。

欢呼声

XML

命名空间

<t:RadDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:t="clr-namespace:Telerik.Windows.Documents.Model;assembly=Telerik.Windows.Documents" 

xmlns:s="clr-namespace:Telerik.Windows.Documents.Model.Styles;assembly=Telerik.Windows.Documents" 

xmlns:r="clr-namespace:Telerik.Windows.Documents.Model.Revisions;assembly=Telerik.Windows.Documents" 

xmlns:n="clr-namespace:Telerik.Windows.Documents.Model.Notes;assembly=Telerik.Windows.Documents" xmlns:th="clr-namespace:Telerik.Windows.Documents.Model.Themes;assembly=Telerik.Windows.Documents" 

xmlns:custom1="clr-namespace:TAS2;assembly=RadRichTextBoxExtensions" 

xmlns:custom2="clr-namespace:;assembly=RadRichTextBoxExtensions" version="1.2" LayoutMode="Paged" LineSpacing="1" LineSpacingType="Auto" ParagraphDefaultSpacingAfter="30" ParagraphDefaultSpacingBefore="30" SelectedBibliographicStyleName="\APA.XSL" StyleName="defaultDocumentStyle">

XML代码段

<custom1:RoomGroupRangeStart  RoomID="26" RoomName="Bathroom" />
<custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="48" Level="1" Name="Plumbing"    ParentID="1"/>
</custom1:SemanticRangeStart.Product>
<custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="49" Level="2" Name="Central Heating" ParentID="48" />
</custom1:SemanticRangeStart.Product>
<custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="50" Level="3" Name="Gas" ParentID="49" />
</custom1:SemanticRangeStart.Product>

首次尝试

select 
    nodes.node.value( '@ID', 'int' ) Id,
    nodes.node.value( '@Name', 'varchar(max)' ) Name,
    nodes.node.value( '@ParentID', 'int' ) ParentId
from    
    @xml.nodes( '//*:Products' ) nodes ( node )


select
    nodes.node.value ( '@RoomID', 'int' ) RoomID,
    nodes.node.value ( '@RoomName', 'varchar(max)' ) RoomName
from    
    @xml.nodes( '//*:RoomGroupRangeStart' ) nodes ( node )

1 个答案:

答案 0 :(得分:1)

试试这样:

我添加了一个带有虚拟命名空间的根节点和几个重复的结构......

DECLARE @x XML=
'<t:RadDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                xmlns:t="clr-namespace:Telerik.Windows.Documents.Model;assembly=Telerik.Windows.Documents" 
                xmlns:s="clr-namespace:Telerik.Windows.Documents.Model.Styles;assembly=Telerik.Windows.Documents" 
                xmlns:r="clr-namespace:Telerik.Windows.Documents.Model.Revisions;assembly=Telerik.Windows.Documents" 
                xmlns:n="clr-namespace:Telerik.Windows.Documents.Model.Notes;assembly=Telerik.Windows.Documents" xmlns:th="clr-namespace:Telerik.Windows.Documents.Model.Themes;assembly=Telerik.Windows.Documents" 
                xmlns:custom1="clr-namespace:TAS2;assembly=RadRichTextBoxExtensions" 
                xmlns:custom2="clr-namespace:;assembly=RadRichTextBoxExtensions" version="1.2" LayoutMode="Paged" LineSpacing="1" LineSpacingType="Auto" ParagraphDefaultSpacingAfter="30" ParagraphDefaultSpacingBefore="30" SelectedBibliographicStyleName="\APA.XSL" StyleName="defaultDocumentStyle">
  <custom1:RoomGroupRangeStart RoomID="26" RoomName="Bathroom" />
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="48" Level="1" Name="Plumbing" ParentID="1" />
  </custom1:SemanticRangeStart.Product>
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="49" Level="2" Name="Central Heating" ParentID="48" />
  </custom1:SemanticRangeStart.Product>
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="50" Level="3" Name="Gas" ParentID="49" />
  </custom1:SemanticRangeStart.Product>

  <custom1:RoomGroupRangeStart RoomID="27" RoomName="Test" />
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="48" Level="1" Name="Test1" ParentID="1" />
  </custom1:SemanticRangeStart.Product>
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="49" Level="2" Name="Test2" ParentID="48" />
  </custom1:SemanticRangeStart.Product>
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="50" Level="3" Name="Test3" ParentID="49" />
  </custom1:SemanticRangeStart.Product>

  <custom1:RoomGroupRangeStart RoomID="28" RoomName="OneMore" />
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="48" Level="1" Name="OneMore1" ParentID="1" />
  </custom1:SemanticRangeStart.Product>
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="49" Level="2" Name="OneMore2" ParentID="48" />
  </custom1:SemanticRangeStart.Product>
  <custom1:SemanticRangeStart.Product>
    <t:Products HasChild="True" ID="50" Level="3" Name="OneMore3" ParentID="49" />
  </custom1:SemanticRangeStart.Product>
</t:RadDocument>';
SELECT @x;

您可以像这样查询

WITH XMLNAMESPACES('clr-namespace:Telerik.Windows.Documents.Model;assembly=Telerik.Windows.Documents' AS t
                  ,'clr-namespace:TAS2;assembly=RadRichTextBoxExtensions' AS custom1
                  ,DEFAULT 'http://schemas.microsoft.com/winfx/2006/xaml/presentation')
,Numbered AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowInx
          ,CASE WHEN The.Node.value('fn:local-name(.)','varchar(max)') = 'RoomGroupRangeStart' THEN 'Room' ELSE 'Product' END AS NodeType
          ,CAST('<node>' + CAST(The.Node.query('.') AS VARCHAR(MAX)) + '</node>' AS XML) AS TheNode
    FROM @x.nodes('/t:RadDocument/*') AS The(Node)
)
,DistinctRooms AS
(
    SELECT Numbered.*
          ,TheNode.value('(*//@RoomID)[1]','int') AS RoomID
          ,TheNode.value('(*//@RoomName)[1]','varchar(max)') AS RoomName 
    FROM Numbered
    WHERE NodeType='Room'
)

SELECT 
       dr.*
      ,RelatedProducts.TheNode.value('(*//@HasChild)[1]','bit') AS HasChild
      ,RelatedProducts.TheNode.value('(*//@ID)[1]','int') AS ProductID
      ,RelatedProducts.TheNode.value('(*//@Level)[1]','int') AS Level
      ,RelatedProducts.TheNode.value('(*//@Name)[1]','varchar(max)') AS ProductName
      ,RelatedProducts.TheNode.value('(*//@ParentID)[1]','int') AS ParentID

FROM DistinctRooms AS dr
CROSS APPLY 
(
    SELECT products.*
    FROM Numbered AS products
    WHERE products.NodeType='Product'
      AND products.RowInx BETWEEN dr.RowInx AND (SELECT ISNULL(MIN(x.RowInx),1000000) FROM DistinctRooms AS x WHERE x.RowInx>dr.RowInx )
) AS RelatedProducts;

结果

1   26  Bathroom    1   48  1   Plumbing         1
1   26  Bathroom    1   49  2   Central Heating 48
1   26  Bathroom    1   50  3   Gas             49
5   27  Test        1   48  1   Test1            1
5   27  Test        1   49  2   Test2           48
5   27  Test        1   50  3   Test3           49
9   28  OneMore     1   48  1   OneMore1         1
9   28  OneMore     1   49  2   OneMore2        48
9   28  OneMore     1   50  3   OneMore3        49