我在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
答案 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