从 XML 返回可变数量的属性作为逗号分隔值

Eri*_*ing 8 xml sql-server extended-events xquery

过度延伸

在阻塞进程报告和死锁 XML 的 SQL Server 扩展事件中,可以获取多个 SQL 句柄值以识别引发事件中涉及的查询。

由于可能涉及 1 个或多个 SQL 句柄,因此可靠地查询 XML 以检索所有这些句柄可能会很困难,并且还会使更简单的 XQuery 不正确,因为它仅检索第一个存储的值。

sqlhandle = bd.value('(process/executionStack/frame/@sqlhandle)[1]', 'varchar(130)'),
Run Code Online (Sandbox Code Playgroud)

用于说明的示例 XML 片段如下所示:

<executionStack>
      <frame line="1" stmtend="108" sqlhandle="0x020000008d18260040e407ba48fc247b0cb6121c21c2cf2b0000000000000000000000000000000000000000" />
      <frame line="1" stmtend="108" sqlhandle="0x02000000dd847b18dcaa4a09a89f56595186fcf91da8a7f70000000000000000000000000000000000000000" />
</executionStack>
Run Code Online (Sandbox Code Playgroud)

此 SQL Fiddle提供了更完整的示例。

我已经做到了这一点:

SELECT 
    sql_handle = 
        @x.query('for $s in //executionStack/frame return $s');  
Run Code Online (Sandbox Code Playgroud)

但这并没有得到我所追求的。扩展该查询以使用该@sqlhandle属性会引发错误:

SELECT 
    sql_handle = 
        @x.query('for $s in //executionStack/frame/@sqlhandle return $s');  
Run Code Online (Sandbox Code Playgroud)

消息 2396,级别 16,状态 1,第 60 行 XQuery [query()]:属性不得出现在元素外部

我怎样才能像这样查询 XML 以将所有列出的 SQL 句柄作为逗号分隔列表返回?

Dav*_*oft 7

尝试这样的事情:

SELECT x.d.value('@name','varchar(200)') name, f.sqlhandles
FROM @x.nodes('//data') x(d)
CROSS APPLY 
(
  SELECT string_agg(n.f.value('@sqlhandle','varchar(200)'),',') sqlhandles
  from x.d.nodes('.//executionStack/frame') n(f)
 ) f
Run Code Online (Sandbox Code Playgroud)


Mar*_*ith 5

要克服错误消息“属性可能不会出现在元素之外”,您可以使用该string函数。

 SELECT @x.query('
                for $s in  //process/executionStack/frame/@sqlhandle
                return string($s)  
                ').value('.', 'varchar(max)')
Run Code Online (Sandbox Code Playgroud)

上面返回一个空格分隔的列表,但由于 SQL 句柄本身不能包含空格,在这种情况下,您只需使用 aREPLACE即可获得所需的逗号分隔的最终结果。

或者做

 SELECT @x.query('
                for $s in  //process/executionStack/frame/@sqlhandle
                return concat(",",string($s))
                ').value('substring(./text()[1], 2)', 'varchar(max)')
Run Code Online (Sandbox Code Playgroud)

或者你可以使用

SELECT REPLACE(
    @x.query('data(//process/executionStack/frame/@sqlhandle)').value('.', 'varchar(max)'), 
    ' ',
    ',')
Run Code Online (Sandbox Code Playgroud)

或者另一种选择,不带concat,由 Paul White 在评论中提供

SELECT 
    sql_handles = 
    @x.query
    (
        '
        for $h in (//executionStack/frame/@sqlhandle)
        return 
        (
            ",", 
            string($h)
        )
        '
    ).value
    (
        'substring(./text()[1], 3)', 
        'nvarchar(max)'
    );
Run Code Online (Sandbox Code Playgroud)