How do I query repeating XML child nodes inside parent repeating nodes? - sql-server

I have the following XML stored in an nText column (not my design, older database). I need to pull the PolicyNumber and the CvgCode that is a property of Coverage child node.
<efs:Request
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:efs="http://www.slsot.org/efs"
xsi:schemaLocation="http://www.slsot.org/efs
http://efs.slsot.org/efs/xsd/SlsotEfsSchema2.xsd">
<EfsVersion>2.0</EfsVersion>
<Batch BatchType="N" AgLicNo="12345" ItemCnt="69">
<EFSPolicy>
<PolicyNumber>POL12345</PolicyNumber>
<Binder>0086592YZ</Binder>
<TransType>N</TransType>
<Insured>Dummy Co LLC</Insured>
<ZipCode>75225</ZipCode>
<ClassCd>99930</ClassCd>
<PolicyFee>35.00</PolicyFee>
<TotalTax>36.62</TotalTax>
<TotalStampFee>1.13</TotalStampFee>
<TotalGross>792.75</TotalGross>
<EffectiveDate>09/17/2018</EffectiveDate>
<ExpirationDate>09/17/2019</ExpirationDate>
<IssueDate>09/20/2018</IssueDate>
<ContUntilCancl>N</ContUntilCancl>
<FedCrUnion>N</FedCrUnion>
<AORFlag>N</AORFlag>
<CustomID>043684</CustomID>
<WindStormExclusion>N</WindStormExclusion>
<CorrectionReEntry>N</CorrectionReEntry>
<Coverages>
<Coverage CvgCode="9325">720.00</Coverage>
</Coverages>
<Securities>
<Company CoNumber="80101168">100.00</Company>
</Securities>
</EFSPolicy>
<EFSPolicy>
...
</EFSPolicy>
</Batch>
</efs:Request>
And here is the SQL code I am using to extract the PolicyNumber (so far).
with cte_table(BatchID, xmlData)
AS
(SELECT BatchID, CAST(CAST(xmlData AS VARCHAR(MAX)) AS XML) from
Batches)
select
s.BatchID
,t.c.value('PolicyNumber[1]', 'varchar(max)') as PolicyNumber
from cte_table as s
cross apply s.xmlData.nodes('/*:Request/Batch/EFSPolicy') as t(c)
where BatchID in (select batchID from Batches where CreateDate between '1/1/19' and getdate())
I have tried a second CROSS APPLY on the Coverages node, but that was giving me all the Coverage values (not CvgCode property) for every batch, so my result set was 100+ times too many rows. I assume that was due to the 2nd CROSS APPLY, is there a INNER JOIN type CROSS APPLY?

You need to declare your namespaces to retrieve the data:
DECLARE #XML xml = '<efs:Request
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:efs="http://www.slsot.org/efs"
xsi:schemaLocation="http://www.slsot.org/efs
http://efs.slsot.org/efs/xsd/SlsotEfsSchema2.xsd">
<EfsVersion>2.0</EfsVersion>
<Batch BatchType="N" AgLicNo="12345" ItemCnt="69">
<EFSPolicy>
<PolicyNumber>POL12345</PolicyNumber>
<Binder>0086592YZ</Binder>
<TransType>N</TransType>
<Insured>Dummy Co LLC</Insured>
<ZipCode>75225</ZipCode>
<ClassCd>99930</ClassCd>
<PolicyFee>35.00</PolicyFee>
<TotalTax>36.62</TotalTax>
<TotalStampFee>1.13</TotalStampFee>
<TotalGross>792.75</TotalGross>
<EffectiveDate>09/17/2018</EffectiveDate>
<ExpirationDate>09/17/2019</ExpirationDate>
<IssueDate>09/20/2018</IssueDate>
<ContUntilCancl>N</ContUntilCancl>
<FedCrUnion>N</FedCrUnion>
<AORFlag>N</AORFlag>
<CustomID>043684</CustomID>
<WindStormExclusion>N</WindStormExclusion>
<CorrectionReEntry>N</CorrectionReEntry>
<Coverages>
<Coverage CvgCode="9325">720.00</Coverage>
</Coverages>
<Securities>
<Company CoNumber="80101168">100.00</Company>
</Securities>
</EFSPolicy>
<EFSPolicy>
</EFSPolicy>
</Batch>
</efs:Request>';
WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' as xsi,
'http://www.slsot.org/efs' AS efs)
SELECT EFS.[Policy].value('(./PolicyNumber/text())[1]','varchar(25)') AS PolicyNumber,
EFS.[Policy].value('(./Coverages/Coverage/#CvgCode)[1]','int') AS CvgCode --Assumes only 1 CvgCode per policy
FROM (VALUES(#XML)) V(X)
CROSS APPLY V.X.nodes('efs:Request/Batch/EFSPolicy') EFS([Policy]);

Related

Include Blank Tag in XML

Using the below SQL query I am generating an XML File like below.
SELECT CAST((SELECT
(
SELECT
ICase,
DPCRef
FROM
#HD HD WHERE HD.OrdRef=PICK.OrdRef
GROUP BY
ICase,
DPCRef
FOR XML PATH('HD'), TYPE
),
(
SELECT
PCode,
SOLnNt,
(
SELECT SSCCRef
FROM #SSCC LM
WHERE LD.OrdRef = LM.OrdRef AND LD.PCode=LM.PCode
GROUP BY
SSCCRef
FOR XML PATH(''), ROOT('SSCC'), TYPE
)
FROM #LD LD
WHERE LD.OrdRef = PICK.OrdRef
GROUP BY
PCode,
SOLnNt
FOR XML PATH('LD'), TYPE
)
FROM #PICK PICK
GROUP BY OrdRef
FOR XML PATH('PICK'), ROOT('PickOrder')) AS XML) AS OrdersPickingConfirmationXML
Result:
<PICK>
<HD>
<CustCode>PAV001</CustCode>
<OrdRef>813804</OrdRef>
</HD>
<LD>
<PCode>PROD0001</PCode>
<Rotation>14/D004193</Rotation>
<SSCC>
<SSCCRef>TEST 1</SSCCRef>
<SSCCRef>TEST1</SSCCRef>
</SSCC>
</LD>
</PICK>
Sometime there will be no data in the #SSCC table.So that time that SSCC tag is not showing in XML.If there is no data I need to show it as </SSCC>. Is there anyway that I can get blank tag </SSCC>

sql tvp vs xml speed in stored procedure are the same??? Is my testing or logic flawed?

I'm an accidental DBA charged with speeding up all our sql servers. I've got a highly used query with a horrible average worker time. I noticed it uses XML to pass data to a stored procedure. Query plan tells me it spends most of its time converting XML. Everything I've read says XML is about 33% slower than TVP. I rewrote the SP using TVP and compared times using the method:
SELECT #StartTime=GETDATE()
exec GetTVPData3 #tvp --or XML method
SELECT #EndTime=GETDATE()
SELECT DATEDIFF(ms,#StartTime,#EndTime) AS [Duration in millisecs]
After many runs and averaging out the times.... TVP vs XML has XML winning by 5ms. ????? (550ms vs 545ms) Is my testing or logic flawed?
Both XML and TVP are populated before I get StartTime. I've run this on 2 different SQL test servers with similar results.
The particular code is used in a cross apply. The only difference in the SPs are:
**TVP**
CROSS APPLY (SELECT id AS ProductID, sortorder AS SortOrder FROM #Insert_tvp) Items
**XML**
CROSS APPLY (
SELECT f.id.value('#id', 'int') AS ProductID, f.id.value('#sortorder', 'int') AS SortOrder
FROM #ProductIDs.nodes('list/p')
AS f(id)
) Items
Everything in my head tells me we need to switch to using TVP and get rid of XML. But I can't convince coders without better results.
EDIT: Adding the whole XML SP:
ALTER PROCEDURE [dbo].[ExtendedDataXML]
#HostedSiteID INT,
#ProductIDs XML = NULL,
#ImageType VARCHAR(20) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT
Products.ID AS ItemID,
0 AS ItemType,
Products.SKU,
Products.Title,
HSP.Slug,
Products.Rank,
Products.Rank AS SalesRank,
Products.Status,
Products.LaunchDate,
Products.IsOnline,
Products.IsAutoOffline,
Products.IsSalableOnline,
Products.IsMarketableOnline,
Products.LeadIn, Products.LeadOut,
COALESCE(Products.CaseQuantity, 1) AS CaseQuantity,
COALESCE(Products.MinimumOrderQuantity, 1) AS MinimumOrderQuantity,
Products.QuantityOnHand,
Image.Filename, Image.Width, Image.Height, Image.Alt, Image.Title,
Pricing.Price, Pricing.SalePrice,
Products.TruckShipment,
HSP.NDescription
FROM Products
JOIN HostedSites_Products HSP ON Products.ID = HSP.ProductID
CROSS APPLY (
SELECT f.id.value('#id', 'int') AS ProductID, f.id.value('#sortorder', 'int') AS SortOrder
FROM #ProductIDs.nodes('list/p')
AS f(id)
) Items
OUTER APPLY (
SELECT TOP(1) Filename, Width, Height, Alt, Title
FROM Items_Images
JOIN Images ON Items_Images.ImageID = Images.ID
WHERE Items_Images.ItemID = Products.ID
AND Items_Images.ItemType = 0
AND Images.Type = COALESCE(#ImageType, '.4b')
) Image
OUTER APPLY (
SELECT TOP(1) Price, SalePrice, CurrentPrice
FROM ProductPrices
WHERE ProductPrices.ProductID = Products.ID
ORDER BY LoRange ASC
) Pricing
WHERE Products.ID = Items.ProductID
AND HSP.HostedSiteID = #HostedSiteID
AND HSP.Validated = 1
AND Products.IsMarketableOnline = 1
ORDER BY Items.SortOrder
END
CROSS APPLY means row wise execution! You are parsing your XML over and over...
Your ID-List is - as far as I understand - meant as a filter
Besides the fact, that this was much better done within an inlined TVF (syntax without BEGIN...END you might try this like this:
ALTER PROCEDURE [dbo].[ExtendedDataXML]
#HostedSiteID INT,
#ProductIDs XML = NULL,
#ImageType VARCHAR(20) = NULL
AS
BEGIN
SET NOCOUNT ON;
WITH IDList AS
(
SELECT f.id.value('#id', 'int') AS ProductID, f.id.value('#sortorder', 'int') AS SortOrder
FROM #ProductIDs.nodes('list/p') AS f(id)
)
SELECT
Products.ID AS ItemID,
0 AS ItemType,
Products.SKU,
Products.Title,
HSP.Slug,
Products.Rank,
Products.Rank AS SalesRank,
Products.Status,
Products.LaunchDate,
Products.IsOnline,
Products.IsAutoOffline,
Products.IsSalableOnline,
Products.IsMarketableOnline,
Products.LeadIn, Products.LeadOut,
COALESCE(Products.CaseQuantity, 1) AS CaseQuantity,
COALESCE(Products.MinimumOrderQuantity, 1) AS MinimumOrderQuantity,
Products.QuantityOnHand,
Image.Filename, Image.Width, Image.Height, Image.Alt, Image.Title,
Pricing.Price, Pricing.SalePrice,
Products.TruckShipment,
HSP.NDescription
FROM Products
JOIN HostedSites_Products HSP ON HSP.HostedSiteID = #HostedSiteID AND HSP.Validated = 1 AND Products.ID = HSP.ProductID
INNER JOIN IDList AS Items ON Items.ProductID=Products.ProductID
OUTER APPLY (
SELECT TOP(1) Filename, Width, Height, Alt, Title
FROM Items_Images
JOIN Images ON Items_Images.ImageID = Images.ID
WHERE Items_Images.ItemID = Products.ID
AND Items_Images.ItemType = 0
AND Images.Type = COALESCE(#ImageType, '.4b')
) Image
OUTER APPLY (
SELECT TOP(1) Price, SalePrice, CurrentPrice
FROM ProductPrices
WHERE ProductPrices.ProductID = Products.ID
ORDER BY LoRange ASC
) Pricing
WHERE Products.IsMarketableOnline = 1
ORDER BY Items.SortOrder
END

Behavior of FOR XML AUTO SQL SERVER

I was fiddling with XML AUTO and XML RAW to see how they behave. The test db is AdventureWorks2012.
SELECT TOP 20 Cust.CustomerID AS C1,
Cust.TerritoryID,
OrderHeader.CustomerID AS C2,
OrderHeader.SalesOrderID,
OrderHeader.Status
FROM Sales.Customer Cust
INNER JOIN Sales.SalesOrderHeader OrderHeader
ON Cust.CustomerID = OrderHeader.CustomerID
FOR XML RAW('MyRow'), ELEMENTS
XML RAW's simplicity just puts every element in the same level
<MyRow>
<C1>29825</C1>
<TerritoryID>5</TerritoryID>
<C2>29825</C2>
<SalesOrderID>43659</SalesOrderID>
<Status>5</Status>
While for XML AUTO
SELECT TOP 20 Cust.CustomerID,
Cust.TerritoryID,
OrderHeader.CustomerID,
OrderHeader.SalesOrderID,
OrderHeader.Status
FROM Sales.Customer Cust
INNER JOIN Sales.SalesOrderHeader OrderHeader
ON Cust.CustomerID = OrderHeader.CustomerID
FOR XML AUTO, ELEMENTS
I have
<Cust>
<CustomerID>29825</CustomerID>
<TerritoryID>5</TerritoryID>
<OrderHeader>
<CustomerID>29825</CustomerID>
<SalesOrderID>43659</SalesOrderID>
<Status>5</Status>
</OrderHeader>
</Cust>
XML AUTO decides to group all under Cust tag. How does it come to this conclusion that Cust somehow encloses and "at a higher level" than OrderHeader. Why does it decide to group all OrderHeader's columns under OrderHeader tag and not the same for Cust ? Before executing I thought that it would be
<Cust>
<CustomerID>29825</CustomerID>
<TerritoryID>5</TerritoryID>
</Cust>
<OrderHeader>
<CustomerID>29825</CustomerID>
<SalesOrderID>43659</SalesOrderID>
<Status>5</Status>
</OrderHeader>
Update
It's a hunch but I start to think SQL Server will take the table of the column first mentioned to be the outer tag,
For example,
SELECT TOP 20 OrderHeader.CustomerID,,
Cust.CustomerID,
Cust.TerritoryID,
OrderHeader.SalesOrderID,
OrderHeader.Status
Even when I mix the column order, it will still group columns of OrderHeader together, and Cust is a subgroup
<OrderHeader>
<CustomerID>29825</CustomerID>
<SalesOrderID>43659</SalesOrderID>
<Status>5</Status>
<Cust>
<CustomerID>29825</CustomerID>
<TerritoryID>5</TerritoryID>
</Cust>
</OrderHeader>

SQL Server 2012: Select xml with repeated and ungrouped set of elements

For the XML below:
<Document>
<ID>01</ID>
<RaitingDate>2006-05-04T18:13:51.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner1</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:52.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner2</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:53.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner3</MinimumRatingPartner>
</Document>
I would like to generate the following table:
RatingDate MRP
----------------------- ---------------------
2006-05-04 18:13:51.000 MinimumRatingPartner1
2006-05-04 18:13:52.000 MinimumRatingPartner2
2006-05-04 18:13:53.000 MinimumRatingPartner3
Now I am getting:
RatingDate MRP
----------------------- ---------------------
2006-05-04 18:13:51.000 MinimumRatingPartner1
2006-05-04 18:13:52.000 MinimumRatingPartner1
2006-05-04 18:13:53.000 MinimumRatingPartner1
2006-05-04 18:13:51.000 MinimumRatingPartner2
2006-05-04 18:13:52.000 MinimumRatingPartner2
2006-05-04 18:13:53.000 MinimumRatingPartner2
2006-05-04 18:13:51.000 MinimumRatingPartner3
2006-05-04 18:13:52.000 MinimumRatingPartner3
2006-05-04 18:13:53.000 MinimumRatingPartner3
Using this query:
DECLARE #XML XML =
'<Document>
<ID>01</ID>
<RaitingDate>2006-05-04T18:13:51.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner1</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:52.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner2</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:53.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner3</MinimumRatingPartner>
</Document>'
SELECT
RatingDate = s.value('text()[1]', 'datetime')
,MRP =r.value('text()[1]', 'nvarchar(50)')
FROM
#XML.nodes('Document') as D(V)
cross apply
D.V.nodes('./RaitingDate') as Q(S)
cross apply
D.V.nodes('./MinimumRatingPartner') as M(R)
order by MRP, RatingDate
I have tried couple other queries, but without success.
Please note: XML structure cannot be changed.
Your XML appears to depend on ordered pairs (first partner goes with first date, second partner goes with second date etc etc). Not only that, but both columns are listed within the same parent node. So you'll have to do something like this. Lucky for you xml is order sensitive.
DECLARE #XML XML =
'<Document>
<ID>01</ID>
<RaitingDate>2006-05-04T18:13:51.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner1</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:52.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner2</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:53.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner3</MinimumRatingPartner>
</Document>'
SELECT MinimumRatingPartner, RatingDate FROM
(SELECT
D.V.value('text()[1]', 'datetime') AS RatingDate,
ROW_NUMBER() over (order by ##rowcount) AS RowNum
FROM #XML.nodes('Document/RaitingDate') as D(V)) Dates
INNER JOIN
(SELECT
D.V.value('text()[1]', 'nvarchar(50)') AS MinimumRatingPartner,
ROW_NUMBER() over (order by ##rowcount) AS RowNum
FROM #XML.nodes('Document/MinimumRatingPartner') as D(V)) Partners
ON Dates.RowNum = Partners.RowNum
Probably not the best solution, but works for the given xml
SELECT RaitingDate,MinimumRatingPartner
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY RaitingDate) AS Num
,RaitingDate
FROM
(
SELECT
Node.Data.value('(.)[1]','DATETIME') as RaitingDate
FROM #XML.nodes('/Document/RaitingDate') Node(Data)
) AS A
) AS DateTable
JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY MinimumRatingPartner) AS Num
,MinimumRatingPartner
FROM
(
SELECT
Node.Data.value('(.)[1]','VARCHAR(50)') as MinimumRatingPartner
FROM #XML.nodes('/Document/MinimumRatingPartner') Node(Data)
) AS B
) AS PartnerTable
ON DateTable.Num=PartnerTable.Num

How to get parameter values for dm_exec_sql_text

I'm running the following statement to see what queries are executing in sql server:
select *
from sys.dm_exec_requests r
cross apply sys.dm_exec_sql_text(r.sql_handle)
where r.database_id = DB_ID('<dbname>')
The sql text that comes back is parameterized:
(#Parm0 int) select * from foo where foo_id = #Parm0
Is there any way to get the values for the parameters that the statement is using? Say by joining to another table perhaps?
Edit : Remus is correct, this will only bring out the compiled versions on the first time that the query plan hit the cache, not subsequent runs.
You should be able to get the parameters from the query plan, since it contains the last parameters used. Altering your code:
select *
from sys.dm_exec_requests r
cross apply sys.dm_exec_query_plan(plan_handle) as qp
cross apply sys.dm_exec_sql_text(r.sql_handle)
where r.database_id = DB_ID('<dbname>')
You will find the final column of the query plan is query_plan, an xml version of the query plan which you can manually inspect, at the bottom of the XML are the parameters, or if you fancy the challenge use XML parsing and XQuery to pull out the ParameterList tags
A query that give the login name, hour of execution and query as text of last events, if you can give a hand to the join of sys.dm_exec_query_stats, but it works
SELECT distinct
s.login_name,
qs.creation_time
,SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE qs.statement_end_offset END
- qs.statement_start_offset)/2) + 1) AS statement_text
FROM sys.dm_exec_sessions S
LEFT JOIN sys.dm_exec_connections AS c ON S.session_id = c.session_id
,sys.dm_exec_query_stats QS --qs on c.most_recent_sql_handle = qs.sql_handle
OUTER APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE ST.text LIKE '%yourKeyWord%' and s.login_name <> 'NT SERVICE\SQLSERVERAGENT'
order by qs.creation_time desc
In case someone stumble upon this thread looking for a proper solution (which the other answers sadly lack), I found this helpful post from mssqltips.
I cleaned-up and tweaked the query a little bit to make this one:
-- cleanup
IF OBJECT_ID('tempdb..#compiledValue') IS NOT NULL
DROP TABLE #compiledValue
GO
-- Prepare temp table #compiledValue
SELECT
OBJECT_NAME(est.objectid) ObjectName,
DB_NAME(est.dbid) DBName,
eqs.last_execution_time,
est.text,
(eqs.statement_start_offset / 2) + 1 AS statement_start_offset,
(IIF(eqs.statement_end_offset = -1, DATALENGTH(est.text), eqs.statement_end_offset) - eqs.statement_start_offset) / 2 + 1 AS statement_end_offset,
TRY_CONVERT(XML,
SUBSTRING(etqp.query_plan,
CHARINDEX('<ParameterList>',etqp.query_plan),
CHARINDEX('</ParameterList>',etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>',etqp.query_plan) )) AS statement_params
INTO #compiledValue
FROM sys.dm_exec_query_stats eqs
CROSS APPLY sys.dm_exec_sql_text(eqs.sql_handle) est
CROSS APPLY sys.dm_exec_text_query_plan(eqs.plan_handle, eqs.statement_start_offset, eqs.statement_end_offset) etqp
SELECT
cvalue.last_execution_time,
cvalue.DBName,
cvalue.ObjectName,
SUBSTRING(cvalue.text,cvalue.statement_start_offset,cvalue.statement_end_offset) AS sql_text,
pc.compiled.value('#Column', 'nvarchar(128)') AS Parameterlist,
pc.compiled.value('#ParameterCompiledValue', 'nvarchar(128)') AS [compiled Value]
FROM #compiledValue cvalue
OUTER APPLY cvalue.statement_params.nodes('//ParameterList/ColumnReference') AS pc(compiled)
WHERE cvalue.text NOT LIKE '%#compiledValue%' -- ignore these queries based on temp table name
ORDER BY cvalue.last_execution_time DESC
GO
-- cleanup
DROP TABLE #compiledValue
GO
It works quite well, and each parameters will have its own line.
For instance:
If you are using a version prior to SQL Server 2012 or Amazon RDS where the TRY_CONVERT function does not exist, this is a variation of the Indigo query that will work.
-- cleanup
IF OBJECT_ID('tempdb..#compiledValue') IS NOT NULL
DROP TABLE #compiledValue
GO
-- Prepare temp table #compiledValue
SELECT
OBJECT_NAME(est.objectid) ObjectName,
DB_NAME(est.dbid) DBName,
eqs.last_execution_time,
est.text,
(eqs.statement_start_offset / 2) + 1 AS statement_start_offset,
(IIF(eqs.statement_end_offset = -1, DATALENGTH(est.text), eqs.statement_end_offset) - eqs.statement_start_offset) / 2 + 1 AS statement_end_offset,
--TRY_CONVERT(XML,
-- SUBSTRING(etqp.query_plan,
-- CHARINDEX('<ParameterList>',etqp.query_plan),
-- CHARINDEX('</ParameterList>',etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>',etqp.query_plan) )) AS statement_params,
CASE
WHEN CHARINDEX('<ParameterList>', etqp.query_plan) > 0
THEN CONVERT(XML,
SUBSTRING(etqp.query_plan,
CHARINDEX('<ParameterList>', etqp.query_plan),
CHARINDEX('</ParameterList>', etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>', etqp.query_plan) ))
ELSE NULL
END AS statement_params
INTO #compiledValue
FROM sys.dm_exec_query_stats eqs
CROSS APPLY sys.dm_exec_sql_text(eqs.sql_handle) est
CROSS APPLY sys.dm_exec_text_query_plan(eqs.plan_handle, eqs.statement_start_offset, eqs.statement_end_offset) etqp
SELECT
cvalue.last_execution_time,
cvalue.DBName,
cvalue.ObjectName,
SUBSTRING(cvalue.text,cvalue.statement_start_offset,cvalue.statement_end_offset) AS sql_text,
pc.compiled.value('#Column', 'nvarchar(128)') AS Parameterlist,
pc.compiled.value('#ParameterCompiledValue', 'nvarchar(128)') AS [compiled Value]
FROM #compiledValue cvalue
OUTER APPLY cvalue.statement_params.nodes('//ParameterList/ColumnReference') AS pc(compiled)
WHERE cvalue.text NOT LIKE '%#compiledValue%' -- ignore these queries based on temp table name
ORDER BY cvalue.last_execution_time DESC
GO
-- cleanup
DROP TABLE #compiledValue
GO

Resources