【问题标题】:How to organize a XML variable content into a table (untyped data)如何将 XML 变量内容组织成表格(无类型数据)
【发布时间】:2026-02-15 06:15:01
【问题描述】:

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

Image of the database filtered by a provided number

只要我无权访问文档并且我不知道它们的结构(非类型化数据),我需要找到一种机制来转换将此 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

【问题讨论】:

  • 所以,您希望我们了解它们的结构并为您提供将 xml 转换为 db 表行的代码,对吧?为什么你认为这是可能的?
  • 其实不是。我正在寻找一种通用解决方案,该解决方案能够识别 xml 结构并对其进行组织,而无需声明我正在寻找的变量的名称(我不知道)。
  • 那你还得等一等,人工智能还没发明出来
  • 如果您需要有关您正在尝试的解决方案的帮助或需要反馈,这是一回事。但是您是否只是发布了您想做的事情并要求 SO 为您做这件事?
  • 对不起,你是对的,我本可以更具体一些,应该就一个例子征求意见。这就是我想要做的,它逐行放置我的节点。我将分两部分发布:

标签: sql sql-server xml reporting-services


【解决方案1】:

调用 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

【讨论】:

    最近更新 更多