解析来自SQL Server表列的XML并拆分为多行。

huangapple go评论61阅读模式
英文:

Parsing XML from a SQL Server table column into multiple rows

问题

SQL Server Standard 2017 on Windows Server 2019

我有一个 SQL Server 表,其中包含一个 XML 列,用于存储自定义数据

create table CustomerCrossReferences 
(
    customer BigInt, 
    product BigInt, 
    customColumns XML
)

customColumns 列包含以下格式的 XML 数据

insert into CustomerCrossReferences 
values (69731, 157,  
'<CustomColumnsCollection>
  <CustomColumn>
    <Name>MOI</Name>
    <DataType>0</DataType>
    <Value>10% max</Value>
  </CustomColumn>
  <CustomColumn>
    <Name>PRO</Name>
    <DataType>0</DataType>
    <Value>26% min</Value>
  </CustomColumn>
  <CustomColumn>
    <Name>FAT</Name>
    <DataType>0</DataType>
    <Value />
  </CustomColumn>
  <CustomColumn>
    <Name>WAT</Name>
    <DataType>0</DataType>
    <Value />
  </CustomColumn>
  <CustomColumn>
    <Name>FMT</Name>
    <DataType>0</DataType>
    <Value>None</Value>
  </CustomColumn>
</CustomColumnsCollection>')

我需要使用这些数据在 SQL Server Report Writer 中构建报表数据集,选择与 Customer/Product 配对的 Name 对应的 Value。我不会在报表中使用 DataType。

目前,我考虑在报表结构中使用以下格式创建数据集

Customer    Product    Name   DataType   Value
-------------------------------------------------
69731       157        MOI    0          10% max
69731       157        PRO    0          26% min
69731       157        FAT    0          
69731       157        WAT    0          
69731       157        FMT    0          

我可以使用以下方式创建这个数据集:

select
  customer
  ,product 
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Name)[1]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/DataType)[1]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Value)[1]', 'varchar(max)')
from
  CustomerCrossReferences
UNION ALL
select
  customer
  ,product 
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Name)[2]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/DataType)[2]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Value)[2]', 'varchar(max)')
from
  CustomerCrossReferences
UNION ALL
select
  customer
  ,product 
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Name)[3]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/DataType)[3]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Value)[3]', 'varchar(max)')
from
  CustomerCrossReferences

虽然这个方法有效,但对于我需要考虑的约20个 CustomColumn 数据元素来说可能会很繁琐。

我的问题是是否有更好的处理方法,无论是更简洁/高效的查询语句,还是能够直接在 Report Builder 中访问 XML 数据。谢谢。

英文:

SQL Server Standard 2017 on Windows Server 2019

I have a SQL Server table that contains an XML column to capture custom data

create table CustomerCrossReferences 
(
    customer BigInt, 
    product BigInt, 
    customColumns XML
)

The customColumns column contains XML data in the following format

insert into CustomerCrossReferences 
values (69731, 157,  
'<CustomColumnsCollection>
  <CustomColumn>
    <Name>MOI</Name>
    <DataType>0</DataType>
    <Value>10% max</Value>
  </CustomColumn>
  <CustomColumn>
    <Name>PRO</Name>
    <DataType>0</DataType>
    <Value>26% min</Value>
  </CustomColumn>
  <CustomColumn>
    <Name>FAT</Name>
    <DataType>0</DataType>
    <Value />
  </CustomColumn>
  <CustomColumn>
    <Name>WAT</Name>
    <DataType>0</DataType>
    <Value />
  </CustomColumn>
  <CustomColumn>
    <Name>FMT</Name>
    <DataType>0</DataType>
    <Value>None</Value>
  </CustomColumn>
</CustomColumnsCollection>')

I need to use this data to build a dataset in a report built in SQL Server Report Writer, selecting Value corresponding to the Name for the Customer/Product pairing. I won't be using DataType in the report.

At the moment I am thinking I should create a dataset in the following format to use in within my report structure

Customer    Product    Name   DataType   Value
-------------------------------------------------
69731       157        MOI    0          10% max
69731       157        PRO    0          26% min
69731       157        FAT    0          
69731       157        WAT    0          
69731       157        FMT    0          

I can create this dataset with the following:

select
  customer
  ,product 
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Name)[1]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/DataType)[1]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Value)[1]', 'varchar(max)')
from
  CustomerCrossReferences
UNION ALL
select
  customer
  ,product 
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Name)[2]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/DataType)[2]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Value)[2]', 'varchar(max)')
from
  CustomerCrossReferences
UNION ALL
select
  customer
  ,product 
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Name)[3]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/DataType)[3]', 'varchar(max)')
  ,customColumns.value('(/CustomColumnsCollection/CustomColumn/Value)[3]', 'varchar(max)')
from
  CustomerCrossReferences

While this works it will be cumbersome as I have approx 20 CustomColumn data elements to consider.

My question is whether there is a better way of handling this, either as a more concise/efficient query statement, or by being able to directly address the XML data within Report Builder. Thanks

答案1

得分: 3

你可以使用XQuery的nodes()方法以行格式获取你的XML数据,类似以下方式:

SELECT	cc.customer, cc.product
,	n.value('(Name/text())[1]', 'nvarchar(100)') AS Name
,	n.value('(DataType/text())[1]', 'int') AS DataType
,	n.value('(Value/text())[1]', 'nvarchar(100)') AS Value
FROM	CustomerCrossReferences cc
CROSS APPLY customColumns.nodes('/CustomColumnsCollection/CustomColumn') n(n)

结合value()方法,你可以检索CustomColumn的各个元素。

英文:

You can use XQuery nodes() method to get your xml data in row format. something like:

SELECT	cc.customer, cc.product
,	n.value('(Name/text())[1]', 'nvarchar(100)') AS Name
,	n.value('(DataType/text())[1]', 'int') AS DataType
,	n.value('(Value/text())[1]', 'nvarchar(100)') AS Value
FROM	CustomerCrossReferences cc
CROSS APPLY customColumns.nodes('/CustomColumnsCollection/CustomColumn') n(n)

Combined with value() method, you can retrieve individual elements of CustomColumn.

huangapple
  • 本文由 发表于 2023年5月22日 01:25:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76301108.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定