使用SQL从XML中提取元素

问题描述 投票:-1回答:1

我有一个情况

  • 存储在表中的Xml执行计划
  • 需要从xml计划中过滤ColumnReference元素及其属性

样本元素

<ColumnReference Database="[Adventureworks]" Schema="[dbo]" Table="[Product]" Column="ProductID" />

挑战:ColumnReference有多个层次结构,需要提取所有这些

预期产出如下表所示:

Database | Schema | Table | Column

示例数据集:(运行下面的代码,您将在temptable中获取名为#t的数据集)

    CREATE TABLE Employee 
    (
        EmpID INT NOT NULL , 
        EmpName VARCHAR(50) NOT NULL, 
        Designation VARCHAR(50) NULL, 
        Department VARCHAR(50) NULL, 
        JoiningDate DATETIME NULL,
        CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED (EmpID)
    )

    INSERT INTO Employee 
    (EmpID, EmpName, Designation, Department, JoiningDate) VALUES 
    (1, 'CHIN YEN', 'LAB ASSISTANT', 'LAB', GETDATE()),
    (2, 'MIKE PEARL', 'SENIOR ACCOUNTANT', 'ACCOUNTS', GETDATE()),
    (3, 'GREEN FIELD', 'ACCOUNTANT', 'ACCOUNTS', GETDATE()),
    (4, 'DEWANE PAUL', 'PROGRAMMER', 'IT', GETDATE()),
    (5, 'MATTS', 'SR. PROGRAMMER', 'IT', GETDATE()),
    (6, 'PLANK OTO', 'ACCOUNTANT', 'ACCOUNTS', GETDATE())
create proc itemployee
as 
select EmpName, Designation  from Employee where department = 'it'

go 

exec itemployee


SELECT 
  'itemployee ' as SP_Name, 
  query_plan into #t  FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle)
WHERE 
  object_id('itemployee') = objectid;

用于提取输出的查询:

SELECT 
  AnyColRef.value('@Table', 'nvarchar(250)') AS [Table], 
  AnyColRef.value('@Column', 'nvarchar(250)') AS [Column] 
FROM 
  #t t
  CROSS APPLY t.query_plan.nodes('//ColumnReference') A(AnyColRef);
sql sql-server xml tsql xml-parsing
1个回答
3
投票

你提供的是不够的......对于你的下一个问题,请尝试创建一个mcve (a stand-alone sample to reproduce your issue)

挑战:ColumnReference可用于多个层次结构,需要提取所有这些层次结构

作为快速拍摄,您可以尝试以下方法:

SELECT AnyColRef.value('@Database','nvarchar(250)') AS [Database]
      ,AnyColRef.value('@Schema','nvarchar(250)') AS [Schema]
      ,AnyColRef.value('@Table','nvarchar(250)') AS [Table]
      ,AnyColRef.value('@Column','nvarchar(250)') AS [Column]
FROM YourTable t
CROSS APPLY t.YourXMLColumn.nodes('//ColumnReference') A(AnyColRef);

简而言之: 深度搜索(由//ColumnReference的双斜线触发)将在XML中的任何位置搜索具有此名称的任何元素。所有这些元素都作为派生集返回,其中每个元素都返回自己的行(这由.nodes()完成)。原生XML方法.value()将最终检索属性的iternal值(由@指示)。

UPDATE

最好是提供您想要阅读的XML样本,但是对于上面的代码来说,重现您的问题,它也有所帮助。

您的问题是:XML声明了一个默认命名空间。有三种方法可以解决这个问题:

  1. a)使用带前缀的WITHXMLNAMESPACES
  2. b)使用WITHXMLNAMESPACESDEFUALT
  3. a)使用带前缀的内部声明
  4. b)使用default element namespace的内部声明
  5. 使用通配符

这个

WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS ns)
SELECT
  AnyColRef.value('@Table', 'nvarchar(250)') AS [Table], 
  AnyColRef.value('@Column', 'nvarchar(250)') AS [Column] 
FROM 
  #t t
  CROSS APPLY t.query_plan.nodes('//ns:ColumnReference') A(AnyColRef);

- 或这个

WITH XMLNAMESPACES(DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT
  AnyColRef.value('@Table', 'nvarchar(250)') AS [Table], 
  AnyColRef.value('@Column', 'nvarchar(250)') AS [Column] 
FROM 
  #t t
  CROSS APPLY t.query_plan.nodes('//ColumnReference') A(AnyColRef);

- 或这个

    SELECT
      AnyColRef.value('@Table', 'nvarchar(250)') AS [Table], 
      AnyColRef.value('@Column', 'nvarchar(250)') AS [Column] 
    FROM 
      #t t
      CROSS APPLY t.query_plan.nodes('declare namespace ns="http://schemas.microsoft.com/sqlserver/2004/07/showplan";//ns:ColumnReference') A(AnyColRef);

- 或这个

    SELECT
      AnyColRef.value('@Table', 'nvarchar(250)') AS [Table], 
      AnyColRef.value('@Column', 'nvarchar(250)') AS [Column] 
    FROM 
      #t t
      CROSS APPLY t.query_plan.nodes('declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan" ;//ColumnReference') A(AnyColRef);

- 或这个

SELECT
  AnyColRef.value('@Table', 'nvarchar(250)') AS [Table], 
  AnyColRef.value('@Column', 'nvarchar(250)') AS [Column] 
FROM 
  #t t
  CROSS APPLY t.query_plan.nodes('//*:ColumnReference') A(AnyColRef);

一般建议是:尽可能具体。命名空间不仅仅是一个花哨的附加组件,而且非常重要,可以处理具有相同名称的不同元素(通常在组合各种XML时)。只有在您可以确定不需要命名空间的情况下,才使用easy-cheesy通配符。我个人更喜欢WITH XMLNAMESPACESDEFAULT的方法,因为它最接近给定的XML。

© www.soinside.com 2019 - 2024. All rights reserved.