【问题标题】:How to extract multiple tag values from XML column in SQL Server如何从 SQL Server 中的 XML 列中提取多个标记值
【发布时间】:2022-01-27 06:32:48
【问题描述】:

我想知道如何从单个 XML 行中提取多个值,问题是这个 XML 值有时有重复的 (name, id, email) 标签子, 例如:

<foo>
    <name>
        Dacely Lara Camilo
    </name>
    <id>
        001-1942098-2
    </id>
    <email>
        myuncletouchme@gmail.com
    </email>
</foo>
<foo>
    <name>
        Alba Elvira Castro
    </name>
    <id>
        001-0327959-2
    </id>
    <email>
        4doorsmorehorse@hotmail.com
    </email>
</foo>

有时该列中的数据可能是这样的

<foo>
    <name>
        Nelson Antonio Jimenez
    </name>
    <id>
        001-0329459-3
    </id>
    <email>
        gsucastillo@tem.com
    </email>
</foo>
<foo>
    <name>
        Emelinda Serrano
    </name>
    <id>
        001-0261732-4
    </id>
    <email>
        gucastillo@tem.com
    </email>
</foo>
<foo>
    <name>
        Nelson Antonio Jimenez
    </name>
    <id>
        001-0329259-3
    </id>
    <email>
        gucastillo@tem.com
    </email>
</foo>
<foo>
    <name>
        Emelinda Serrano
    </name>
    <id>
        001-0268332-4
    </id>
    <email>
        gucastillo@tem.com
    </email>
</foo>

我希望所有这些都被转置为一行,就像这样:

我当前的代码只是提取第一对,如果有帮助的话,

WITH BASEDATA (ID, SIGNATURE, X) AS (
    SELECT TOP 50
        A.ID_SIGNATURE,
        A.SIGNATURE,
        A.XML
    FROM DWH.DIM_CORE_SIGNATURE A
)SELECT
    ID,
    A.value('(id)[1]', 'nvarchar(max)') AS ID_SIGNATURE,
    A.value('(name)[1]', 'nvarchar(max)') AS NAME,
    A.value('(email)[1]', 'nvarchar(max)') AS EMAIL
FROM BASEDATA
CROSS APPLY X.nodes('//foo') AS SIGNATURE(A)

【问题讨论】:

  • 提问时,您需要提供minimal reproducible example: (1) DDL 和样本数据填充,即 CREATE 表和 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上述#1 中的样本数据。 (4) 您的 SQL Server 版本 (SELECT @@version;)。全部在问题内,没有图片。
  • 您的 SQL 似乎工作正常,我不关注这个问题。 [dbfiddle]((dbfiddle.uk/…) (尽管我建议您选择比允许 10 亿个字符更好的数据类型...)

标签: sql sql-server xml tsql


【解决方案1】:

值得注意的点:

  • .nodes('/foo') 方法具有更好、性能更高的 XPath 表达式。
  • 最好使用.value('(id/text())[1]',... 原因。
  • 正如@Lamu 已经建议的那样,最好使用真实数据类型而不是全面使用nvarchar(max)

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<foo>
    <name>Dacely Lara Camilo</name>
    <id>001-1942098-2</id>
    <email>myuncletouchme@gmail.com</email>
</foo>
<foo>
    <name>Alba Elvira Castro</name>
    <id>001-0327959-2</id>
    <email>4doorsmorehorse@hotmail.com</email>
</foo>')
, (N'<foo>
    <name>Nelson Antonio Jimenez</name>
    <id>001-0329459-3</id>
    <email>gsucastillo@tem.com</email>
</foo>
<foo>
    <name>Emelinda Serrano</name>
    <id>001-0261732-4</id>
    <email>gucastillo@tem.com</email>
</foo>
<foo>
    <name>Nelson Antonio Jimenez</name>
    <id>001-0329259-3</id>
    <email>gucastillo@tem.com</email>
</foo>
<foo>
    <name>Emelinda Serrano</name>
    <id>001-0268332-4</id>
    <email>gucastillo@tem.com</email>
</foo>');
-- DDL and sample data population, end

SELECT ID,
    c.value('(id/text())[1]', 'char(13)') AS ID_SIGNATURE,
    c.value('(name/text())[1]', 'nvarchar(30)') AS NAME,
    c.value('(email/text())[1]', 'nvarchar(128)') AS EMAIL
FROM @tbl
    CROSS APPLY xmldata.nodes('/foo') AS t(c);

输出

+----+---------------+----------------------+-----------------------------+
| ID | ID_SIGNATURE  |         NAME         |            EMAIL            |
+----+---------------+----------------------+-----------------------------+
|  1 | 001-1942098-2 | Dacely Lara Camilo   | myuncletouchme@gmail.com    |
|  1 | 001-0327959-2 | Alba Elvira Castro   | 4doorsmorehorse@hotmail.com |
|  2 | 001-0329459-3 | Nelson Antonio Jimen | gsucastillo@tem.com         |
|  2 | 001-0261732-4 | Emelinda Serrano     | gucastillo@tem.com          |
|  2 | 001-0329259-3 | Nelson Antonio Jimen | gucastillo@tem.com          |
|  2 | 001-0268332-4 | Emelinda Serrano     | gucastillo@tem.com          |
+----+---------------+----------------------+-----------------------------+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多