使用SQL从XML提取元素

时间:2019-04-25 05:34:25

标签: sql sql-server xml tsql xml-parsing

我遇到了情况

  • 存储在表中的Xml执行计划

  • 需要从xml计划中过滤ColumnReference元素及其属性

样本元素

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

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

预期输出为以下结构中的表格:

Database | Schema | Table | Column

样本数据集:(运行以下代码,您将获得称为#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);

1 个答案:

答案 0 :(得分: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()最终将检索属性的内部值(由@表示)。

更新

最好是提供您要阅读的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。