在SQL中从XML查询提取字符串

时间:2019-05-28 07:08:33

标签: sql sql-server xml

在SQL Server 2012中,我有一个表DEFINITIONS和其中的一列,该列的值为XML,列的名称为“ XML”。我想从XML列(在参数标签中)提取字符串“ [CDATA [xxxx]]”。我该怎么办?

XML示例值:

<CatalogItem subType="0" type="82">
   <id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
   <name>Test White</name>
   <description />
   <attributes>0</attributes>
   <parameters>&lt;conditions&gt;&lt;condition grouping="or"&gt;&lt;prop-key&gt;usb_device_serial_number&lt;/prop-key&gt;&lt;op-key&gt;equals&lt;/op-key&gt;&lt;value&gt;&lt;![CDATA[gdefgd||]]&gt;&lt;/value&gt;&lt;/condition&gt;&lt;/conditions&gt;</parameters>
   <customParameterNames />
   <enforceProducts>
     <Product type="WIN" />
   </enforceProducts>
   </CatalogItem>

更新1

此查询解决了我的问题:

if object_id('dbo.cdata') is not null drop table dbo.cdata;
create table dbo.cdata(
  x xml
);
insert into dbo.cdata(x)
  SELECT XML FROM [HQ-MC-SRV-01].[dbo].[DEFINITIONS]
select
  xv.v.value('.', 'nvarchar(max)') as cdata
from dbo.cdata
cross apply
  cdata.x.nodes(
   '//parameters'
  ) as pp(p)
cross apply (
  values(
   cast(pp.p.value(
     '.', 'nvarchar(max)'
   ) as xml)
  )
 ) as xp(p)
cross apply
 xp.p.nodes('//value') as xv(v)
;

非常感谢Andrei Odegov

更新2

我也必须使用先前的查询从该XML中提取“ serialNumber”和“ endUser”。

<CatalogItem subType="0" type="93">
 <id>9d6825e6-fa89-44e1-8e0f-61768016624c</id>
 <name>tteesstt</name>
 <description />
 <attributes>0</attributes>
 <entries>
  <entry>
    <serialNumber>zsxxdx</serialNumber>
    <userType>user</userType>
    <endUser>farhad@drf.local</endUser>
    <description />
  </entry>
 </entries>
</CatalogItem>

更新3

 <CatalogItem subType="0" type="12">
  <id>169d6139-bdb6-4fff-88e6-09f00dd2f155</id>
  <name>za</name>
  <description />
  <attributes>0</attributes>
  <SIDMode>true</SIDMode>
  <nameIdentificationType>1</nameIdentificationType>
  <entries>
   <entry>
    <name>farhad</name>
    <path>CN=farhad,CN=Users,DC=DCVLAB,DC=LOCAL</path>
    <uid>F7A84834EAC8984AA7FBEAD7A5539432</uid>
    <serverName>192.168.7.2</serverName>
    <sid>S-1-5-21-907365782-933549064-1582919620-1103</sid>
    <type>user</type>
   </entry>
  </entries>
 </CatalogItem>

1 个答案:

答案 0 :(得分:3)

考虑到您的测试数据,您可以尝试修改以下代码:

declare @x xml = '
<CatalogItem subType="0" type="82">
   <id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
   <name>Test White</name>
   <description />
   <attributes>0</attributes>
   <parameters>&lt;conditions&gt;&lt;condition grouping="or"&gt;&lt;prop-key&gt;usb_device_serial_number&lt;/prop-key&gt;&lt;op-key&gt;equals&lt;/op-key&gt;&lt;value&gt;&lt;![CDATA[gdefgd||]]&gt;&lt;/value&gt;&lt;/condition&gt;&lt;/conditions&gt;</parameters>
   <customParameterNames />
   <enforceProducts>
     <Product type="WIN" />
   </enforceProducts>
   </CatalogItem>
';

select cast(@x.value('(//parameters)[1]', 'nvarchar(max)') as xml).query('//value/text()') as cdata;

输出

+----------+
|  cdata   |
+----------+
| gdefgd|| |
+----------+

更新:

if object_id('dbo.cdata') is not null drop table dbo.cdata;

create table dbo.cdata(
  x xml
);

insert into dbo.cdata(x)
  values ('
<CatalogItem subType="0" type="82">
   <id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
   <name>Test White</name>
   <description />
   <attributes>0</attributes>
   <parameters>&lt;conditions&gt;&lt;condition grouping="or"&gt;&lt;prop-key&gt;usb_device_serial_number&lt;/prop-key&gt;&lt;op-key&gt;equals&lt;/op-key&gt;&lt;value&gt;&lt;![CDATA[gdefgd||]]&gt;&lt;/value&gt;&lt;value&gt;&lt;![CDATA[foo]]&gt;&lt;/value&gt;&lt;/condition&gt;&lt;/conditions&gt;</parameters>
   <parameters>&lt;conditions&gt;&lt;condition grouping="or"&gt;&lt;prop-key&gt;usb_device_serial_number&lt;/prop-key&gt;&lt;op-key&gt;equals&lt;/op-key&gt;&lt;value&gt;&lt;![CDATA[gdefgd||170]]&gt;&lt;/value&gt;&lt;value&gt;&lt;![CDATA[foo170]]&gt;&lt;/value&gt;&lt;/condition&gt;&lt;/conditions&gt;</parameters>
   <customParameterNames />
   <enforceProducts>
     <Product type="WIN" />
   </enforceProducts>
   </CatalogItem>
'), ('
<CatalogItem subType="0" type="82">
   <id>7c75be9f-d490-4ff5-81ed-064349f4efde</id>
   <name>Test White</name>
   <description />
   <attributes>0</attributes>
   <parameters>&lt;conditions&gt;&lt;condition grouping="or"&gt;&lt;prop-key&gt;usb_device_serial_number&lt;/prop-key&gt;&lt;op-key&gt;equals&lt;/op-key&gt;&lt;value&gt;&lt;![CDATA[gdefgd||42]]&gt;&lt;/value&gt;&lt;value&gt;&lt;![CDATA[foo42]]&gt;&lt;/value&gt;&lt;/condition&gt;&lt;/conditions&gt;</parameters>
   <customParameterNames />
   <enforceProducts>
     <Product type="WIN" />
   </enforceProducts>
   </CatalogItem>
');

select
  xv.v.value('.', 'nvarchar(max)') as cdata
from dbo.cdata
cross apply
  cdata.x.nodes(
    '//parameters'
  ) as pp(p)
cross apply (
  values(
    cast(pp.p.value(
      '.', 'nvarchar(max)'
    ) as xml)
   )
  ) as xp(p)
cross apply
  xp.p.nodes('//value') as xv(v);

更新#2:

您可以在“ XQuery Language Reference (SQL Server)”中获得有关使用XML数据在Sql Server中工作的更多详细信息。
CROSSOUTER {{ 3}}运算符及其在XML数据中的应用示例。

select
  replace(xv.v.value('.', 'nvarchar(max)'), '|', '') as cdata,
  xci.ci.value('(//serialNumber)[1]', 'nvarchar(15)') as sn,
  xci.ci.value('(entries/entry/endUser)[1]', 'nvarchar(50)') as eu,
  xci.ci.value('(entries/entry/name)[1]', 'nvarchar(50)') as name
from dbo.cdata
cross apply
  cdata.x.nodes('/CatalogItem') as xci(ci)
outer apply
  xci.ci.nodes('parameters') as pp(p)
outer apply (
  values(
    cast(pp.p.value(
      '.', 'nvarchar(max)'
    ) as xml)
   )
  ) as xp(p)
outer apply
  xp.p.nodes('//value') as xv(v);

输出:

+-----------+--------+------------------+--------+
|   cdata   |   sn   |        eu        |  name  |
+-----------+--------+------------------+--------+
| gdefgd    | zsxxdx | farhad@drf.local | NULL   |
| foo       | zsxxdx | farhad@drf.local | NULL   |
| gdefgd170 | zsxxdx | farhad@drf.local | NULL   |
| foo170    | zsxxdx | farhad@drf.local | NULL   |
| NULL      | foobar | user@mail.net    | NULL   |
| NULL      | NULL   | NULL             | farhad |
+-----------+--------+------------------+--------+

使用APPLY在线进行测试。