从 SQL Server 中的 XML 数据类型字段中提取数据

Posted

技术标签:

【中文标题】从 SQL Server 中的 XML 数据类型字段中提取数据【英文标题】:Extract data from XML data type field in SQL Server 【发布时间】:2020-04-16 16:24:34 【问题描述】:

我在 ReportServer 数据库上执行以下查询。

SELECT ItemID, CAST(CAST(Content AS VARBINARY(MAX)) AS XML) Content
FROM dbo.Catalog
WHERE Type = 8

我想提取Content 列的字段列表。 content 列是 XML 数据类型并包含如下 XML:

<SharedDataSet xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/shareddatasetdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
  <DataSet Name="DataSet1">
    <Query>
      <DataSourceReference>DDSDB</DataSourceReference>
      <CommandText>SELECT z.AccessoryPercent
    ,CASE 
        WHEN z.AccessoryPercent&gt;0.20 Then 1 
        WHEN z.AccessoryPercent &gt;=0.10 THEN 0 
        ELSE -1
    end AS AccessoryState
FROM (
    SELECT (a.FixedPrice - a.NetSalesPrice)/a.FixedPrice AS AccessoryPercent
    FROM acc.Fact_Crm_Accessory a
    )z</CommandText>
    </Query>
    <Fields>
      <Field Name="AccessoryPercent">
        <DataField>AccessoryPercent</DataField>
        <rd:TypeName>System.Decimal</rd:TypeName>
      </Field>
      <Field Name="AccessoryState">
        <DataField>AccessoryState</DataField>
        <rd:TypeName>System.Int32</rd:TypeName>
      </Field>
    </Fields>
  </DataSet>
</SharedDataSet>

我的预期结果是:

   DataSetName      Field
   -------------------------------------
   DataSet1         AccessoryPercent
   DataSet1         AccesspryState

提前致谢

编辑:我编写了以下查询以便于查询。

CREATE TABLE #t (data XML)

INSERT INTO #t 
VALUES('<SharedDataSet xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/shareddatasetdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
<DataSet Name="DataSet1">
    <Query>
      <DataSourceReference>DDSDB</DataSourceReference>
      <CommandText>SELECT z.AccessoryPercent
    ,CASE 
        WHEN z.AccessoryPercent&gt;0.20 Then 1 
        WHEN z.AccessoryPercent &gt;=0.10 THEN 0 
        ELSE -1
    end AS AccessoryState
FROM (
    SELECT (a.FixedPrice - a.NetSalesPrice)/a.FixedPrice AS AccessoryPercent
    FROM acc.Fact_Crm_Accessory a
    )z</CommandText>
    </Query>
    <Fields>
      <Field Name="AccessoryPercent">
        <DataField>AccessoryPercent</DataField>
        <TypeName>System.Decimal</TypeName>
      </Field>
      <Field Name="AccessoryState">
        <DataField>AccessoryState</DataField>
        <TypeName>System.Int32</TypeName>
      </Field>
    </Fields>
  </DataSet>
</SharedDataSet>')

SELECT  *
FROM #t AS t

【问题讨论】:

【参考方案1】:

(1) 我们需要考虑默认命名空间。

(2) 第二个CROSS APPLY 处理数据集与其字段之间的一对多关系。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (xmldata XML);

INSERT INTO @tbl 
VALUES('<SharedDataSet xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/shareddatasetdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
<DataSet Name="DataSet1">
    <Query>
      <DataSourceReference>DDSDB</DataSourceReference>
      <CommandText>SELECT z.AccessoryPercent
    ,CASE 
        WHEN z.AccessoryPercent&gt;0.20 Then 1 
        WHEN z.AccessoryPercent &gt;=0.10 THEN 0 
        ELSE -1
    end AS AccessoryState
FROM (
    SELECT (a.FixedPrice - a.NetSalesPrice)/a.FixedPrice AS AccessoryPercent
    FROM acc.Fact_Crm_Accessory a
    )z</CommandText>
    </Query>
    <Fields>
      <Field Name="AccessoryPercent">
        <DataField>AccessoryPercent</DataField>
        <TypeName>System.Decimal</TypeName>
      </Field>
      <Field Name="AccessoryState">
        <DataField>AccessoryState</DataField>
        <TypeName>System.Int32</TypeName>
      </Field>
    </Fields>
  </DataSet>
</SharedDataSet>');
-- DDL and sample data population, end

;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/reporting/2010/01/shareddatasetdefinition')
SELECT c.value('@Name','VARCHAR(30)') AS DataSetName      
    , f.value('@Name','VARCHAR(30)') AS Field      
FROM @tbl AS tbl
    CROSS APPLY tbl.xmldata.nodes('/SharedDataSet/DataSet') AS t(c)
    CROSS APPLY t.c.nodes('Fields/Field') AS f(f);

输出

+-------------+------------------+
| DataSetName |      Field       |
+-------------+------------------+
| DataSet1    | AccessoryPercent |
| DataSet1    | AccessoryState   |
+-------------+------------------+

【讨论】:

以上是关于从 SQL Server 中的 XML 数据类型字段中提取数据的主要内容,如果未能解决你的问题,请参考以下文章

动态获取 SQL Server 中不同列中的 XML 数据类型值

从sql server中的xml中提取数据

Spring JDBC for SQL Server - 使用 SQLXML 数据类型产生 SQLServerException:不允许从数据类型 xml 到 nvarchar(max) 的隐式转换

将 XML 文档从 SQL SERVER 插入到 Oracle

SQL Server XML 类型化列大小差异

将字符串转换为xml并插入Sql Server