sql - SQL - 如何从表中的 XML 字段中提取多个属性
问题描述
我正在尝试对一个表运行 SQL 查询,该表具有一个包含 XML 数据的字段,但该 XML 包含多个需要转换为一个字段的值。请注意,该字段是 XML 内容,但实际字段类型设置为 nvarchar(max),而不是 xml。
编辑:版本是SQL Server 2014 Express Edition
我有一张这样的表:[有市场的客户列表]
我想在同一行中提取“marketCode”值(逗号分隔):
|CompanyCode|CompanyName|MarketCode,MarketCode,MarketCode,etc.|Phone|
示例的预期输出(见屏幕截图):
|ABC123|JOHN DEERE|AA,BB,CC,DD|555-123-000|
|DEF456|NEW HOLLLAND|AA,FF,GG,HH,KK|555-456-0000|
解决方案
样本数据
下次请提供文字而不是图片;-)
列Markets
定义为nvarchar(max)
。数据以 unicode(带N
前缀)的形式插入。
create table Company2
(
Code nvarchar(6),
Name nvarchar(11),
Markets nvarchar(max),
Phone nvarchar(12)
);
insert into Company2 (Code, Name, Markets, Phone) values
(N'ABC123',
N'JOHN DEERE',
N'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<license>
<company companyCode="ABC123">
<markets>
<market marketCode="AA"/>
<market marketCode="BB"/>
<market marketCode="CC"/>
<market marketCode="DD"/>
</markets>
</company>
</license>',
N'555-123-0000'),
(N'DEF456',
N'NEW HOLLAND',
N'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<license>
<company companyCode="DEF456">
<markets>
<market marketCode="AA"/>
<market marketCode="FF"/>
<market marketCode="GG"/>
<market marketCode="HH"/>
<market marketCode="KK"/>
</markets>
</company>
</license>',
N'555-456-0000');
解决方案
无法Markets
直接转换XML
为,因为nvarchar(max)
编码与数据中的“utf-8”冲突。我将转换转移到一个单独的公用表表达式 (CTE, cte_convert
) 中,从nvarchar(max)
tovarchar(max)
到XML
。
现在可以使用下一个 CTE( cte_parse
)将 XMLc.MarketsXML.nodes()
中的节点提取<market>
到新列m.Market
中。从该列@marketCode
中提取属性作为所需值。
然后使用子查询for xml path('')
来连接这些值。
with cte_convert as
(
select c.Code, c.Name, convert(XML, convert(varchar(max), c.Markets)) as MarketsXML, c.Phone
from Company2 c
),
cte_parse as
(
select c.Code, c.Name, m.Market.value('@marketCode', 'nvarchar(10)') as MarketCode, c.Phone
from cte_convert c
outer apply c.MarketsXML.nodes('/license/company/markets/market') as m(Market)
)
select cp.Code,
cp.Name,
stuff(( select ',' + cp2.MarketCode as MC
from cte_parse cp2
where cp2.Code = cp.Code
for xml path(''), type).value('.', 'nvarchar(max)'),1,1,'') as MarketCodes,
cp.Phone
from cte_parse cp
group by cp.Code, cp.Name, cp.Phone;
结果
Code Name MarketCodes Phone
------ ----------- -------------- ------------
ABC123 JOHN DEERE AA,BB,CC,DD 555-123-0000
DEF456 NEW HOLLAND AA,FF,GG,HH,KK 555-456-0000
此原始解决方案使用从 SQL Server 2017 开始可用的string_agg()函数。
样本数据
备注:该列Markets
被定义为XML
反映其内容。
create table Company
(
Code nvarchar(6),
Name nvarchar(11),
Markets XML,
Phone nvarchar(12)
);
insert into Company (Code, Name, Markets, Phone) values
('ABC123',
'JOHN DEERE',
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<license>
<company companyCode="ABC123">
<markets>
<market marketCode="AA"/>
<market marketCode="BB"/>
<market marketCode="CC"/>
<market marketCode="DD"/>
</markets>
</company>
</license>',
'555-123-0000'),
('DEF456',
'NEW HOLLAND',
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<license>
<company companyCode="DEF456">
<markets>
<market marketCode="AA"/>
<market marketCode="FF"/>
<market marketCode="GG"/>
<market marketCode="HH"/>
<market marketCode="KK"/>
</markets>
</company>
</license>',
'555-456-0000');
解决方案
with cte_parse as
(
select c.Code, c.Name, m.Market.value('@marketCode', 'nvarchar(10)') as MarketCode, c.Phone
from Company c
outer apply c.Markets.nodes('/license/company/markets/market') as m(Market)
)
select cp.Code, cp.Name, string_agg(cp.MarketCode, ',') as MarketCodes, cp.Phone
from cte_parse cp
group by cp.Code, cp.Name, cp.Phone;
推荐阅读
- android - 使用非默认 FirebaseApp 初始化 FirebaseMessage 和 FirebaseAnalytics
- git - 解决 Tableau 工作簿 TWB 文件中的 GIT 合并冲突
- regex - Symfony4 在使用带有 slug 生成的函数请求 actor_show 时出现消息错误
- python-pptx - How to alter a presentation to display all texts in upper case?
- java - 在服务器-客户端套接字通信方面需要一些帮助
- python-3.x - 从 csv 文件中提取特定列,并使用 Python 转换为 Lambda 中的字符串
- python - 在 python 中使用 Seaborn 进行配对分布
- android - 如何获得半透明状态栏?
- java - 如何使用 Spring Data Mongo DB 仅检索文档的特定字段?
- java - 循环构造函数对象循环java