【问题标题】:Query from multiple XML columns in SQL Server从 SQL Server 中的多个 XML 列查询
【发布时间】:2020-06-12 07:08:40
【问题描述】:

环境:SQL Server 2016; “真实”数据的抽象示例。

从第一个查询到包含 XML 数据的表,我有一个包含以下列的 SQL 结果集:

  1. ID(整数)
  2. 名称 (XML)
  3. 时代 (XML)
  4. 值 (XML)

第 2-4 列包含多个 XML 格式的值,例如

姓名:

  • 第 1 行:<name>TestR1</name><name>TestR2</name>...
  • 第 2 行:<name>TestS1</name><name>TestS2</name>...

次:

  • 第 1 行:<time>0.1</time><time>0.2</time>...
  • 第 2 行:<time>-0.1</time><time>-0.2</time>...

价值观:

  • 第 1 行:<value>1.1</value><value>1.2</value>...
  • 第 2 行:<value>-1.1</value><value>-1.2</value>...

所有 XML 列的 XML 包含完全相同数量的元素。

我现在想要的是创建一个具有以下输出的选择:

| ID | Name   | Time | Value |
+----+--------+------+-------+
| 1  | TestR1 |  0.1 |  1.1  |
| 1  | TestR1 |  0.2 |  1.2  |
| .. | ...... | .... | ..... |
| 2  | TestS1 | -0.1 | -1.1  |
| 2  | TestS2 | -0.2 | -1.2  |
| .. | ...... | .... | ..... |

对于单列 CROSS APPLY 工作正常:

SELECT ID, N.value('.', 'nvarchar(50)') AS ExtractedName
FROM <source>
CROSS APPLY <source>.nodes('/name') AS T(N)

应用多个 CROSS APPLY 语句对我来说毫无意义。

我想如果我为每个列创建选择,然后生成单独的结果集并对所有结果集执行选择,它会起作用 但这很可能不是最佳解决方案,因为我正在为每个附加列复制选择。

任何关于如何设计这样的查询的建议将不胜感激!

【问题讨论】:

    标签: sql-server xml tsql


    【解决方案1】:

    我建议这种方法:

    首先,我创建一个声明的表变量并用您的示例数据填充它以模拟您的问题。这称为“MCVE”,请尝试在下一个问题中自己提供。

    DECLARE @tbl TABLE(ID INT, Names XML,Times XML,[Values] XML);
    INSERT INTO @tbl VALUES
     (1,'<name>TestR1</name><name>TestR2</name>','<time>0.1</time><time>0.2</time>','<value>1.1</value><value>1.2</value>')
    ,(2,'<name>TestS1</name><name>TestS2</name>','<time>0.3</time><time>0.4</time>','<value>2.1</value><value>2.2</value>');
    

    --查询

    SELECT t.ID
          ,t.Names.value('(/name[sql:column("tally.Nmbr")])[1]','nvarchar(max)') AS [Name]
          ,t.Times.value('(/time[sql:column("tally.Nmbr")])[1]','decimal(10,4)') AS [Time]
          ,t.[Values].value('(/value[sql:column("tally.Nmbr")])[1]','decimal(10,4)') AS [Value]
    FROM @tbl t
    CROSS APPLY
    (   
        SELECT TOP(t.Names.value('count(*)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) Nmbr FROM master..spt_values
    ) tally;
    

    简而言之:

    • 我们通过使用APPLY 创建一个数字列表来创建一个即时计数
    • TOP-子句将这个列表限制为给定行中 &lt;name&gt; 元素的计数。
    • 在这种情况下,我将master..spt_values 作为许多行的源。我们不需要内容,只需要一个适当的列表来创建一个计数。也就是说,如果您的数据库中有物理数字表,那就更好了。
    • 最后,我们可以使用 sql:column() 将计数值引入 XQuery 谓词中,根据元素的位置选择内容。

    【讨论】:

    • 在这种情况下,使用计数表来获取每个元素的正确位置应该是第一个选项。 +1。
    • 非常感谢您的回答。只需几分钟即可实施您的方法,它的工作原理就像一个魅力!
    • 好答案,我这边+1!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2012-10-18
    • 2019-05-20
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    相关资源
    最近更新 更多