【问题标题】:SQL XQuery Selector for Key/Value Pairs键/值对的 SQL XQuery 选择器
【发布时间】:2019-11-18 19:58:38
【问题描述】:

我在这样的列中有一些 xml。

<ScopedWorkflowConfiguration xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/workflow/2012/xaml/activities">
  <appSettings>
    <AppSetting>
      <Key>CurrentWebUri</Key>
      <Value>http://myurl.org</Value>
    </AppSetting>
    <AppSetting>
      <Key>SomethingElse</Key>
      <Value>1</Value>
    </AppSetting>
    <AppSetting>
      <Key>AnotherThing</Key>
      <Value>420</Value>
    </AppSetting>
  </appSettings>
</ScopedWorkflowConfiguration>

试图选择 Value 节点的值。

;WITH Casted AS (SELECT t.Id, t.[Configuration] As XmlData FROM dbo.MyTable AS t)
Select Distinct
     Id
    ,pv.value('//*:Key="CurrentWebUri"/Value', 'nvarchar(max)') As CurrentWebUri
From
    Casted
    Cross Apply Casted.XmlData.nodes(N'//*:ScopedWorkflowConfiguration//*:appSettings//*:AppSetting') AS A(pv)

我知道我很接近 - 但我在此处的语法上遇到了问题://:Key="CurrentWebUri"/Value*

上面的查询导致这个错误:

/需要一个节点或一组节点

你能帮忙吗?

添加一个结果集以供参考以进一步阐明我所追求的:

+----+------------------+------------------+------------------+
| ID | CurrentWebUri    | SomethingElse    |  AnotherThing    |
+----+------------------+------------------+------------------+
|  1 | example.org      |        1         |       420        |
+----+------------------+------------------+------------------+
|  2 | example.com      |        6         |       29         |
+----+------------------+------------------+------------------+

【问题讨论】:

    标签: sql xml xquery xquery-sql


    【解决方案1】:

    缺少默认命名空间声明,并且 XPath 表达式已关闭。随着对所需输出的最新澄清,需要用于 PIVOTing 的动态 SQL。

    SQL

    -- DDL and sample data population, start
    USE tempdb;
    
    DROP TABLE IF EXISTS dbo.tbl;
    
    CREATE TABLE dbo.tbl (ID INT IDENTITY PRIMARY KEY, [Configuration] xml);
    
    INSERT INTO dbo.tbl ([Configuration])
    VALUES ('<ScopedWorkflowConfiguration xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
                                 xmlns="http://schemas.microsoft.com/workflow/2012/xaml/activities">
        <appSettings>
            <AppSetting>
                <Key>CurrentWebUri</Key>
                <Value>http://myurl.org</Value>
            </AppSetting>
            <AppSetting>
                <Key>SomethingElse</Key>
                <Value>1</Value>
            </AppSetting>
            <AppSetting>
                <Key>AnotherThing</Key>
                <Value>420</Value>
            </AppSetting>
        </appSettings>
    </ScopedWorkflowConfiguration>');
    -- DDL and sample data population, end
    
    DECLARE @columns AS NVARCHAR(MAX),
        @SQL AS NVARCHAR(MAX);
    
    ;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/workflow/2012/xaml/activities')
    SELECT TOP(1) @columns = STUFF([Configuration].query('for $s in /ScopedWorkflowConfiguration/appSettings/AppSetting/Key
                               return <x>{concat(",",$s)}</x>')
                       .value('.','varchar(max)'),1,1,'')
    FROM dbo.tbl;
    
    SET @SQL = 
    N';WITH XMLNAMESPACES (DEFAULT ''http://schemas.microsoft.com/workflow/2012/xaml/activities''), rs AS
    ( 
        SELECT ID
            , c.value(''(Key/text())[1]'', ''NVARCHAR(MAX)'') AS [Key]
            , c.value(''(Value/text())[1]'', ''NVARCHAR(MAX)'') AS [Value]
        FROM dbo.tbl as tbl
            CROSS APPLY tbl.[Configuration].nodes(''/ScopedWorkflowConfiguration/appSettings/AppSetting'') AS t(c)
    )
    SELECT ID,' + @columns + N' FROM rs
    PIVOT (
        MAX([Value])
        FOR [Key] IN (' + @columns + N')
    ) AS pvt;
    ';
    
    EXEC sp_executesql @SQL;
    

    输出

    +----+------------------+---------------+--------------+
    | ID |  CurrentWebUri   | SomethingElse | AnotherThing |
    +----+------------------+---------------+--------------+
    |  1 | http://myurl.org |             1 |          420 |
    +----+------------------+---------------+--------------+
    

    【讨论】:

    • 谢谢 - 我应该更清楚要求:我需要查询能够定位特定节点值,例如“CurrentWebUri”。使用索引 [1] 是不够的。
    • 我通过添加谓词调整了 SQL。立即查看。
    • @JasonSmith,只是为了补充这个很好的答案(我这边+1):您可以使用sql:variable("@SearchFor") 而不是xquery 谓词中的文字。这允许声明一个 T-SQL-Variable DECLARE @SearchFor VARCHAR(100)='CurrentWebUri'; 以使其更通用。类似地,我们有 sql:column() 包含当前行的任何列值。
    • @Yitzhak,我不知道我在传达我所追求的目标时哪里出错了——但我更新了原始问题以显示我正在努力实现的结果集。我希望这有助于澄清事情。告诉我。
    • @JasonSmith,我修改了答案以适应您的最新说明。
    猜你喜欢
    • 1970-01-01
    • 2013-09-06
    • 2021-10-31
    • 2021-12-18
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多