如何从 SQL 服务器中的 XML 列中提取多个标签值
How to extract multiple tag values from XML column in SQL Server
我想知道如何从单个 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>
我希望所有的 then 都像这样转置为一行:
我目前的代码只是提取第一对,如果有帮助的话,
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)
要点:
.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 |
+----+---------------+----------------------+-----------------------------+
我想知道如何从单个 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>
我希望所有的 then 都像这样转置为一行:
我目前的代码只是提取第一对,如果有帮助的话,
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)
要点:
.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 |
+----+---------------+----------------------+-----------------------------+