我遇到了情况
存储在表中的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);
答案 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声明了默认名称空间。有三种方法可以解决此问题:
WITHXMLNAMESPACES
WITHXMLNAMESPACES
与DEFUALT
一起使用default element namespace
使用内部声明要么
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 XMLNAMESPACES
与DEFAULT
一起使用的方法,因为它最接近给定的XML。