如何将XML变量内容组织到表中(无类型数据)

时间:2017-05-12 18:57:26

标签: sql sql-server xml reporting-services

我在SQL Server中有一个数据库,其中一个列是一个XML,其内容(根,子和子)可能会根据给定参数的不同而有所不同。

Image of the database filtered by a provided number

只要我无法访问文档并且我不知道他们的结构(无类型数据),我需要找到一种允许我< strong>将此XML列的内容转换为新数据库的变量。

我的意思是:查询将识别我的XML内容(节点数也可以变化),组织根,子和子,将其放入表中。你能不能看看代码并提出一些建议,我怎么能逐行(这是代码所做的)转换成一个表?谢谢!

DECLARE @xmlText VARCHAR(MAX)
SELECT TOP 1 @xmlText = CAST(ContenuTransmission AS VARCHAR(MAX)) FROM pgisCBL.dbo.Transmission WHERE NoReferenceTransmission = '1411130048'
IF OBJECT_ID('tempdb..#xmlTest') IS NOT NULL DROP TABLE #xmlTest -- SELECT * FROM #xmlTest WHERE TagType = 3
SELECT
    ID
    ,Valeur + '>' as Tag
    ,CASE WHEN LEFT(Valeur + '>',2) = '</' AND RIGHT(Valeur + '>',1) = '>'                                       THEN 3 -- EndSection
          WHEN LEFT(Valeur + '>',1) = '<'  AND RIGHT(Valeur + '>',1) = '>' AND CHARINDEX('=', Valeur + '>') > 0  THEN 1 -- Section with values
          WHEN LEFT(Valeur + '>',1) = '<'  AND RIGHT(Valeur + '>',1) = '>' AND CHARINDEX('=', Valeur + '>') = 0  THEN 1 -- Section start
          ELSE 2 -- Value for previous section start
     END AS TagType
INTO #xmlTest
FROM IG.dbo.ftSplitDelimiteMax(@xmlText,'>')
WHERE Valeur + '>' <> '>'

SELECT * FROM #xmlTest

-- IDENTIFY INDENTS AND OUTDENTS AND PUT THE ELEMENTS SIDE BY SIDE
; WITH
    cteOutdent AS (SELECT
                        ID
                        ,REPLACE(REPLACE(Tag,'/',''),'>','') AS Tag
                        ,LEN(REPLACE(REPLACE(Tag,'/',''),'>','')) AS LenTag
                        ,-2 AS Indent
                    FROM #xmlTest
                    WHERE TagType = 3)
,   cteIndent AS (SELECT
                        #xmlTest.ID + 1 AS ID
                        ,#xmlTest.Tag 
                        ,2 AS Indent
                    FROM #xmlTest
                    INNER JOIN cteOutdent 
                    ON cteOutdent.Tag = LEFT(#xmlTest.Tag,cteOutdent.LenTag)
                    WHERE TagType <> 3)
,   cteIndents AS (SELECT DISTINCT
                        ID,
                        Indent
                    FROM cteIndent 
                    UNION
                    SELECT DISTINCT
                        ID,
                        Indent
                    FROM cteOutdent)
SELECT
    a.ID
    ,CASE WHEN b.TagType = 2 THEN a.Tag + b.Tag ELSE a.tag END AS xmlLine
    ,ISNULL(cteIndents.Indent,0) AS Indent
FROM
    #xmlTest a
    LEFT JOIN #xmlTest b
    ON b.id = a.ID + 1
    LEFT JOIN cteIndents ON cteIndents.Id = a.ID
WHERE a.TagType in (1,3)
ORDER BY a.ID

Results of the code

1 个答案:

答案 0 :(得分:0)

名为John Capelletti的函数,其链接由@Shnugo共享:

CREATE FUNCTION [dbo].[ftCollapseXML](@XML xml)

Returns Table 
As Return

with  cte0 as ( 
                  Select Lvl       = 1
                        ,ID        = Cast(1 as int) 
                        ,Pt        = Cast(NULL as int)
                        ,Element   = x.value('local-name(.)','varchar(150)')
                        ,Attribute = cast('' as varchar(150))
                        ,Value     = x.value('text()[1]','varchar(max)')
                        ,XPath     = cast(concat(x.value('local-name(.)','varchar(max)'),'[' ,cast(Row_Number() Over(Order By (Select 1)) as int),']') as varchar(max))
                        ,Seq       = cast(1000000+Row_Number() over(Order By (Select 1)) as varchar(max))
                        ,AttData   = x.query('.') 
                        ,XMLData   = x.query('*') 
                  From   @XML.nodes('/*') a(x) 
                  Union  All
                  Select Lvl       = p.Lvl + 1 
                        ,ID        = Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10
                        ,Pt        = p.ID
                        ,Element   = c.value('local-name(.)','varchar(150)')
                        ,Attribute = cast('' as varchar(150))
                        ,Value     = cast( c.value('text()[1]','varchar(max)') as varchar(max) ) 
                        ,XPath     = cast(concat(p.XPath,'/',c.value('local-name(.)','varchar(max)'),'[',cast(Row_Number() Over(PARTITION BY c.value('local-name(.)','varchar(max)') Order By (Select 1)) as int),']') as varchar(max) )
                        ,Seq       = cast(concat(p.Seq,' ',10000000+Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10) as varchar(max))
                        ,AttData   = c.query('.') 
                        ,XMLData   = c.query('*') 
                  From   cte0 p 
                  Cross  Apply p.XMLData.nodes('*') b(c) 
              )
    , cte1 as (   
                  Select R1 = Row_Number() over (Order By Seq),A.*
                  From  (
                          Select  Lvl,ID,Pt,Element,Attribute,Value,XPath,Seq From cte0
                          Union All
                          Select Lvl       = p.Lvl+1
                                ,ID        = p.ID + Row_Number() over (Order By (Select NULL)) 
                                ,Pt        = p.ID
                                ,Element   = p.Element
                                ,Attribute = x.value('local-name(.)','varchar(150)')
                                ,Value     = x.value('.','varchar(max)')
                                ,XPath     = p.XPath + '/@' + x.value('local-name(.)','varchar(max)')
                                ,Seq       = cast(concat(p.Seq,' ',10000000+p.ID + Row_Number() over (Order By (Select NULL)) ) as varchar(max))
                          From   cte0 p 
                          Cross  Apply AttData.nodes('/*/@*') a(x) 
                        ) A 
               )

Select A.R1
      ,R2  = IsNull((Select max(R1) From cte1 Where Seq Like A.Seq+'%'),A.R1)
      ,A.Lvl
      ,A.ID
      ,A.Pt
      ,A.Element
      ,A.Attribute
      ,A.XPath
      ,Title = Replicate('|---',Lvl-1)+Element+IIF(Attribute='','','@'+Attribute)
      ,A.Value
 From  cte1 A
GO