TSQL XML - 节点属性作为同一查询中的列或行
TSQL XML - Node attributes as columns or rows in same query
我正在处理一个 XML 文件,其节点与此类似:
<Process>
<Step No="1" Types="D" Temp="25" Secs="6" Macro="2">Enable Mixers</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step>
</Process>
DDL:
DROP TABLE IF EXISTS MyXML2
GO
CREATE TABLE MyXML2(ID INT IDENTITY(1,1), c XML)
INSERT MyXML2(c) VALUES
('<Process><Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>')
GO
我需要得到这样的数据库结构(仅针对上面的 1 个“步骤”给出的示例):
StepNumber
ColumnName
ColumnValue
1
Types
D
1
Temp
25
1
Secs
6
1
Macro
2
我目前的工作:我已经能够将每个属性映射到一行中。(编辑:更新为基于上述 DDL 的工作示例)
SELECT
col.value('local-name(.)', 'VARCHAR(50)') AS ColumnName,
col.value('.[1]', 'VARCHAR(MAX)') AS ColumnValue
FROM [MyXML2]
CROSS APPLY [c].nodes('/Process/Step/@*') doc(col)
输出如下:
但我需要“否”属性作为一列。有没有一种方法可以在一个查询中完成这一切?
由于您原来没有提供DDL+DML,所以我提供了两个示例。一个用于 table,它有标识列(我的样本中的 ID),一个没有(这意味着我需要使用 ROW_NUMBER 动态添加一个)
演示一:当我们有标识栏时
-- DDL+DML : this is something that the OP should provide!!!
DROP TABLE IF EXISTS MyXML2
GO
CREATE TABLE MyXML2(ID INT IDENTITY(1,1), c XML)
INSERT MyXML2(c) VALUES
('<Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step>')
GO
-- Solution
;With MyCTE as (
SELECT
MyXML2.ID,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyXML2
CROSS APPLY MyXML2.c.nodes('/Step/@*') doc(Col)
)
select
StepNumber = (SELECT MyIn.ColumnValue from MyCTE as MyIn where MyIn.ColumnName = 'No' and MyIn.ID = MyCTE.ID)
,ColumnName,ColumnValue
from MyCTE
WHERE not ColumnName = 'No'
GO
演示二:当我们没有标识列时
-- DDL+DML : this is something that the OP should provide!!!
DROP TABLE IF EXISTS MyXML
GO
CREATE TABLE MyXML(c XML)
INSERT MyXML(c) VALUES
('<Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step>')
GO
-- Solution
;With MyCTE1 AS (SELECT RN = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), c FROM MyXML)
, MyCTE2 as (
SELECT
MyCTE1.RN,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyCTE1
CROSS APPLY MyCTE1.c.nodes('/Step/@*') doc(Col)
)
select
StepNumber = (SELECT MyIn.ColumnValue from MyCTE2 as MyIn where MyIn.ColumnName = 'No' and MyIn.RN = MyCTE2.RN)
,ColumnName,ColumnValue
from MyCTE2
WHERE not ColumnName = 'No'
GO
结果符合预期:
更新时间:2021-12-06
根据我们得到的新信息,这里有一些新的解决方案和解释。以上应该对未来有类似问题的读者有用。
因此,在上述解决方案中,我关注的是 table 中每一行都有单个 Step
节点的情况。根据新信息,我们可能在同一值中有 Step
的多个节点。此外, Step
节点包裹在另一个节点名称 Process
例如,特定的 XML 值可以是:<Process><Step No="1" Types="D1" Temp="1" Secs="61" Macro="21">Enable Mixers1</Step> <Step No="11" Types="D11" Temp="11" Secs="611" Macro="21">Enable Mixers2</Step> <Step No="111" Types="D111" Temp="111" Secs="6111" Macro="23">Enable Mixers3</Step></Process>
演示三:使用变量,Step
节点结构未知,多个Step
节点
在此演示中,我将反对基于与解决方案一相同方法的解决方案
declare @xml XML = '<Process><Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers2</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>'
-->>> HIGHLY recommended to un-comment below lines and check what I am using as input for the CTE in this solution
--SELECT
-- t.c.value('./@No', 'VARCHAR(128)') as StepNumber,
-- t.c.query ('.') as Types
--from @xml.nodes('Process/.[1]/*')as t(c)
;With MyCTE01 as (
SELECT
t.c.value('./@No', 'INT') as StepNumber,
t.c.query ('.') as MyXML
from @xml.nodes('Process/.[1]/*')as t(c)
)
SELECT
MyCTE01.StepNumber,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyCTE01
CROSS APPLY MyCTE01.MyXML.nodes('/Step/@*') doc(Col)
WHERE not doc.Col.value('local-name(.[1])','VARCHAR(100)') = 'No'
GO
这个解决方案对你有用,但如果 Step
节点的结构总是相同的——这意味着你在讨论期间具有与所有示例中相同的属性,那么我们可以做得更好解决方案...
演示四:使用变量,Step
节点有已知结构,多个Step节点
既然我们知道我们拥有哪个属性,那么我们就可以硬编码使用这些名称。在这种情况下,我们不做这部分,这意味着找到所有属性 CROSS APPLY MyCTE01.MyXML.nodes('/Step/@*')
我们可以使用完全不同的方法,直接获取已知属性的值并使用 UNPIVOT。此解决方案提供了更好的性能,但它不如解决方案三灵活。
declare @xml XML = '<Process><Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers2</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>'
--select
-- t.c.value('./@No', 'VARCHAR(128)') as id,
-- t.c.value('./@Types', 'VARCHAR(128)') as Types,
-- t.c.value('./@Temp', 'VARCHAR(128)') as Temp,
-- t.c.value('./@Secs', 'VARCHAR(128)') as Secs,
-- t.c.value('./@Macro', 'VARCHAR(128)') as Macro,
-- t.c.value('./@Macro', 'VARCHAR(128)') as Macro
--from @xml.nodes('Process/.[1]/*')as t(c)
SELECT StepNumber, Column_Name, Column_Value
FROM(
select
t.c.value('./@No', 'VARCHAR(128)') as StepNumber,
t.c.value('./@Types', 'VARCHAR(128)') as Types,
t.c.value('./@Temp', 'VARCHAR(128)') as Temp,
t.c.value('./@Secs', 'VARCHAR(128)') as Secs,
t.c.value('./@Macro', 'VARCHAR(128)') as Macro
from @xml.nodes('Process/.[1]/*')as t(c)
) p
UNPIVOT
(Column_Value FOR Column_Name IN (Types, Temp, Secs, Macro) )AS unpvt;
GO
注意!如果您使用动态查询并首先在 XML.
中找到属性,则也可以将此方法用于未知结构
演示五:使用变量,Step
个节点有已知结构,多个Step节点
此解决方案与解决方案四(已知结构)具有相同的限制,但除此之外,它仅适用于我们处理单个值(如变量)的情况。因此,如果我们想在 table 上实现它,那么我们可能需要循环所有行,这可能会显着降低性能。 但是当此解决方案满足需求时,它应该会提供最佳性能!
/***BEST SOLUTION - if fits the needs***/
-- XML to Tabular using OPENXML
DECLARE @idoc INT, @xml XML = '<Process><Step No="1" Types="D1" Temp="1" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D11" Temp="11" Secs="611" Macro="21">Enable Mixers2</Step>
<Step No="111" Types="D111" Temp="111" Secs="6111" Macro="23">Enable Mixers3</Step></Process>'
--Create an internal representation of the XML document.
-- Reads the XML text -> parses the text by using the MSXML parser -> and provides the parsed document in a state ready for consumption.
EXEC sp_xml_preparedocument @idoc OUTPUT, @xml;
--SELECT
-- No as StepNumber,
-- Types as Types,
-- Temp as Temp,
-- Secs as Secs,
-- Macro as Macro,
-- NoteValue
--FROM OPENXML (@idoc, '/Process/Step')
-- WITH (
-- -- When OPENXML does not have input of third parameter then we can choose if this will atribute or node
-- -- usig '@No' will bring the value of atribute and using 'No' will bring the value of node
-- No INT '@No' ,
-- Types VARCHAR(128) '@Types',
-- Temp VARCHAR(128) '@Temp' ,
-- Secs VARCHAR(128) '@Secs' ,
-- Macro VARCHAR(128) '@Macro',
-- NoteValue VARCHAR(128) '.'
-- )
SELECT StepNumber, Column_Name, Column_Value
FROM(
SELECT
No as StepNumber,
Types as Types,
Temp as Temp,
Secs as Secs,
Macro as Macro
FROM OPENXML (@idoc, '/Process/Step',1)
WITH (
No INT,
Types VARCHAR(128),
Temp VARCHAR(128),
Secs VARCHAR(128),
Macro VARCHAR(128)
)
) p
UNPIVOT
(Column_Value FOR Column_Name IN (Types, Temp, Secs, Macro) )AS unpvt;
--sp_xml_removedocument free's up the memory.
EXEC sp_xml_removedocument @idoc
GO
所以...我们有多种适合不同情况的方法...但我们仍然需要考虑 tables...
演示六:使用table,Step
节点结构未知,多个Step节点
如果适合(已知结构或使用动态查询),您可以实施演示四,但对于最后一个演示,我将在 table 中有多行的情况下实施演示三方法,每个行行包括具有多个 Step
个节点的 XML
DROP TABLE IF EXISTS MyXML_Tbl
GO
CREATE TABLE MyXML_Tbl(ID INT IDENTITY(1,1), MyXML XML)
GO
INSERT MyXML_Tbl(MyXML) VALUES
('<Process><Step No="1" Types="D1" Temp="1" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D11" Temp="11" Secs="611" Macro="21">Enable Mixers1</Step>
<Step No="111" Types="D111" Temp="111" Secs="6111" Macro="23">Enable Mixers3</Step></Process>')
INSERT MyXML_Tbl(MyXML) VALUES
('<Process><Step No="2" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="22" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="222" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>')
GO
--SELECT * FROM MyXML_Tbl
--GO
--SELECT
-- tb.ID,
-- tx.c.value('./@No', 'VARCHAR(128)') as StepNumber,
-- tx.c.query ('.') as Types
--from MyXML_Tbl tb
--CROSS APPLY tb.MyXML.nodes('Process/.[1]/*')as tx(c)
;With MyCTE01 as (
SELECT
tb.ID,
tx.c.value('./@No', 'VARCHAR(128)') as StepNumber,
tx.c.query ('.') as MyXML
from MyXML_Tbl tb
CROSS APPLY tb.MyXML.nodes('Process/.[1]/*')as tx(c)
)
SELECT
MyCTE01.id,
MyCTE01.StepNumber,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyCTE01
CROSS APPLY MyCTE01.MyXML.nodes('/Step/@*') doc(Col)
WHERE not doc.Col.value('local-name(.[1])','VARCHAR(100)') = 'No'
GO
我希望这是有用的。它应该涵盖讨论中提到的所有情况
我正在处理一个 XML 文件,其节点与此类似:
<Process>
<Step No="1" Types="D" Temp="25" Secs="6" Macro="2">Enable Mixers</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step>
</Process>
DDL:
DROP TABLE IF EXISTS MyXML2
GO
CREATE TABLE MyXML2(ID INT IDENTITY(1,1), c XML)
INSERT MyXML2(c) VALUES
('<Process><Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>')
GO
我需要得到这样的数据库结构(仅针对上面的 1 个“步骤”给出的示例):
StepNumber | ColumnName | ColumnValue |
---|---|---|
1 | Types | D |
1 | Temp | 25 |
1 | Secs | 6 |
1 | Macro | 2 |
我目前的工作:我已经能够将每个属性映射到一行中。(编辑:更新为基于上述 DDL 的工作示例)
SELECT
col.value('local-name(.)', 'VARCHAR(50)') AS ColumnName,
col.value('.[1]', 'VARCHAR(MAX)') AS ColumnValue
FROM [MyXML2]
CROSS APPLY [c].nodes('/Process/Step/@*') doc(col)
输出如下:
但我需要“否”属性作为一列。有没有一种方法可以在一个查询中完成这一切?
由于您原来没有提供DDL+DML,所以我提供了两个示例。一个用于 table,它有标识列(我的样本中的 ID),一个没有(这意味着我需要使用 ROW_NUMBER 动态添加一个)
演示一:当我们有标识栏时
-- DDL+DML : this is something that the OP should provide!!!
DROP TABLE IF EXISTS MyXML2
GO
CREATE TABLE MyXML2(ID INT IDENTITY(1,1), c XML)
INSERT MyXML2(c) VALUES
('<Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step>')
GO
-- Solution
;With MyCTE as (
SELECT
MyXML2.ID,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyXML2
CROSS APPLY MyXML2.c.nodes('/Step/@*') doc(Col)
)
select
StepNumber = (SELECT MyIn.ColumnValue from MyCTE as MyIn where MyIn.ColumnName = 'No' and MyIn.ID = MyCTE.ID)
,ColumnName,ColumnValue
from MyCTE
WHERE not ColumnName = 'No'
GO
演示二:当我们没有标识列时
-- DDL+DML : this is something that the OP should provide!!!
DROP TABLE IF EXISTS MyXML
GO
CREATE TABLE MyXML(c XML)
INSERT MyXML(c) VALUES
('<Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>'),
('<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step>')
GO
-- Solution
;With MyCTE1 AS (SELECT RN = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), c FROM MyXML)
, MyCTE2 as (
SELECT
MyCTE1.RN,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyCTE1
CROSS APPLY MyCTE1.c.nodes('/Step/@*') doc(Col)
)
select
StepNumber = (SELECT MyIn.ColumnValue from MyCTE2 as MyIn where MyIn.ColumnName = 'No' and MyIn.RN = MyCTE2.RN)
,ColumnName,ColumnValue
from MyCTE2
WHERE not ColumnName = 'No'
GO
结果符合预期:
更新时间:2021-12-06
根据我们得到的新信息,这里有一些新的解决方案和解释。以上应该对未来有类似问题的读者有用。
因此,在上述解决方案中,我关注的是 table 中每一行都有单个 Step
节点的情况。根据新信息,我们可能在同一值中有 Step
的多个节点。此外, Step
节点包裹在另一个节点名称 Process
例如,特定的 XML 值可以是:<Process><Step No="1" Types="D1" Temp="1" Secs="61" Macro="21">Enable Mixers1</Step> <Step No="11" Types="D11" Temp="11" Secs="611" Macro="21">Enable Mixers2</Step> <Step No="111" Types="D111" Temp="111" Secs="6111" Macro="23">Enable Mixers3</Step></Process>
演示三:使用变量,Step
节点结构未知,多个Step
节点
在此演示中,我将反对基于与解决方案一相同方法的解决方案
declare @xml XML = '<Process><Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers2</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>'
-->>> HIGHLY recommended to un-comment below lines and check what I am using as input for the CTE in this solution
--SELECT
-- t.c.value('./@No', 'VARCHAR(128)') as StepNumber,
-- t.c.query ('.') as Types
--from @xml.nodes('Process/.[1]/*')as t(c)
;With MyCTE01 as (
SELECT
t.c.value('./@No', 'INT') as StepNumber,
t.c.query ('.') as MyXML
from @xml.nodes('Process/.[1]/*')as t(c)
)
SELECT
MyCTE01.StepNumber,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyCTE01
CROSS APPLY MyCTE01.MyXML.nodes('/Step/@*') doc(Col)
WHERE not doc.Col.value('local-name(.[1])','VARCHAR(100)') = 'No'
GO
这个解决方案对你有用,但如果 Step
节点的结构总是相同的——这意味着你在讨论期间具有与所有示例中相同的属性,那么我们可以做得更好解决方案...
演示四:使用变量,Step
节点有已知结构,多个Step节点
既然我们知道我们拥有哪个属性,那么我们就可以硬编码使用这些名称。在这种情况下,我们不做这部分,这意味着找到所有属性 CROSS APPLY MyCTE01.MyXML.nodes('/Step/@*')
我们可以使用完全不同的方法,直接获取已知属性的值并使用 UNPIVOT。此解决方案提供了更好的性能,但它不如解决方案三灵活。
declare @xml XML = '<Process><Step No="1" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers2</Step>
<Step No="2" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>'
--select
-- t.c.value('./@No', 'VARCHAR(128)') as id,
-- t.c.value('./@Types', 'VARCHAR(128)') as Types,
-- t.c.value('./@Temp', 'VARCHAR(128)') as Temp,
-- t.c.value('./@Secs', 'VARCHAR(128)') as Secs,
-- t.c.value('./@Macro', 'VARCHAR(128)') as Macro,
-- t.c.value('./@Macro', 'VARCHAR(128)') as Macro
--from @xml.nodes('Process/.[1]/*')as t(c)
SELECT StepNumber, Column_Name, Column_Value
FROM(
select
t.c.value('./@No', 'VARCHAR(128)') as StepNumber,
t.c.value('./@Types', 'VARCHAR(128)') as Types,
t.c.value('./@Temp', 'VARCHAR(128)') as Temp,
t.c.value('./@Secs', 'VARCHAR(128)') as Secs,
t.c.value('./@Macro', 'VARCHAR(128)') as Macro
from @xml.nodes('Process/.[1]/*')as t(c)
) p
UNPIVOT
(Column_Value FOR Column_Name IN (Types, Temp, Secs, Macro) )AS unpvt;
GO
注意!如果您使用动态查询并首先在 XML.
中找到属性,则也可以将此方法用于未知结构演示五:使用变量,Step
个节点有已知结构,多个Step节点
此解决方案与解决方案四(已知结构)具有相同的限制,但除此之外,它仅适用于我们处理单个值(如变量)的情况。因此,如果我们想在 table 上实现它,那么我们可能需要循环所有行,这可能会显着降低性能。 但是当此解决方案满足需求时,它应该会提供最佳性能!
/***BEST SOLUTION - if fits the needs***/
-- XML to Tabular using OPENXML
DECLARE @idoc INT, @xml XML = '<Process><Step No="1" Types="D1" Temp="1" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D11" Temp="11" Secs="611" Macro="21">Enable Mixers2</Step>
<Step No="111" Types="D111" Temp="111" Secs="6111" Macro="23">Enable Mixers3</Step></Process>'
--Create an internal representation of the XML document.
-- Reads the XML text -> parses the text by using the MSXML parser -> and provides the parsed document in a state ready for consumption.
EXEC sp_xml_preparedocument @idoc OUTPUT, @xml;
--SELECT
-- No as StepNumber,
-- Types as Types,
-- Temp as Temp,
-- Secs as Secs,
-- Macro as Macro,
-- NoteValue
--FROM OPENXML (@idoc, '/Process/Step')
-- WITH (
-- -- When OPENXML does not have input of third parameter then we can choose if this will atribute or node
-- -- usig '@No' will bring the value of atribute and using 'No' will bring the value of node
-- No INT '@No' ,
-- Types VARCHAR(128) '@Types',
-- Temp VARCHAR(128) '@Temp' ,
-- Secs VARCHAR(128) '@Secs' ,
-- Macro VARCHAR(128) '@Macro',
-- NoteValue VARCHAR(128) '.'
-- )
SELECT StepNumber, Column_Name, Column_Value
FROM(
SELECT
No as StepNumber,
Types as Types,
Temp as Temp,
Secs as Secs,
Macro as Macro
FROM OPENXML (@idoc, '/Process/Step',1)
WITH (
No INT,
Types VARCHAR(128),
Temp VARCHAR(128),
Secs VARCHAR(128),
Macro VARCHAR(128)
)
) p
UNPIVOT
(Column_Value FOR Column_Name IN (Types, Temp, Secs, Macro) )AS unpvt;
--sp_xml_removedocument free's up the memory.
EXEC sp_xml_removedocument @idoc
GO
所以...我们有多种适合不同情况的方法...但我们仍然需要考虑 tables...
演示六:使用table,Step
节点结构未知,多个Step节点
如果适合(已知结构或使用动态查询),您可以实施演示四,但对于最后一个演示,我将在 table 中有多行的情况下实施演示三方法,每个行行包括具有多个 Step
个节点的 XML
DROP TABLE IF EXISTS MyXML_Tbl
GO
CREATE TABLE MyXML_Tbl(ID INT IDENTITY(1,1), MyXML XML)
GO
INSERT MyXML_Tbl(MyXML) VALUES
('<Process><Step No="1" Types="D1" Temp="1" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="11" Types="D11" Temp="11" Secs="611" Macro="21">Enable Mixers1</Step>
<Step No="111" Types="D111" Temp="111" Secs="6111" Macro="23">Enable Mixers3</Step></Process>')
INSERT MyXML_Tbl(MyXML) VALUES
('<Process><Step No="2" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="22" Types="D1" Temp="11" Secs="61" Macro="21">Enable Mixers1</Step>
<Step No="222" Types="D2" Temp="22" Secs="62" Macro="23">Enable Mixers3</Step></Process>')
GO
--SELECT * FROM MyXML_Tbl
--GO
--SELECT
-- tb.ID,
-- tx.c.value('./@No', 'VARCHAR(128)') as StepNumber,
-- tx.c.query ('.') as Types
--from MyXML_Tbl tb
--CROSS APPLY tb.MyXML.nodes('Process/.[1]/*')as tx(c)
;With MyCTE01 as (
SELECT
tb.ID,
tx.c.value('./@No', 'VARCHAR(128)') as StepNumber,
tx.c.query ('.') as MyXML
from MyXML_Tbl tb
CROSS APPLY tb.MyXML.nodes('Process/.[1]/*')as tx(c)
)
SELECT
MyCTE01.id,
MyCTE01.StepNumber,
doc.Col.value('local-name(.[1])','VARCHAR(100)') ColumnName,
doc.Col.value('.[1]','VARCHAR(100)') ColumnValue
FROM MyCTE01
CROSS APPLY MyCTE01.MyXML.nodes('/Step/@*') doc(Col)
WHERE not doc.Col.value('local-name(.[1])','VARCHAR(100)') = 'No'
GO
我希望这是有用的。它应该涵盖讨论中提到的所有情况