如何拆分包含 XML 字符串的 SQL 字段

Posted

技术标签:

【中文标题】如何拆分包含 XML 字符串的 SQL 字段【英文标题】:How can i split SQL field that contains an XML string 【发布时间】:2019-10-01 11:34:06 【问题描述】:

我有一个带有 XML sn-ps 的字段。我想创建一个#TempTable,它将包含 XML 数据的拆分,但只显示两个特定标签之间的任何字符。

字段值看起来像这样(为易读而包装):

<monthdate>2019-07-01</monthdate>
<automitemno>302</automitemno>
<amount>1.190000000000</amount>
<currentamount>0.000000000000</currentamount>
<langitemno>1</langitemno>
<monthdate>2019-07-01</monthdate>
<automitemno>2131</automitemno>
<amount>0.386750000000</amount>
<currentamount>0.000000000000</currentamount>
<langitemno>1</langitemno>

等等。我希望#TempTable 中的列包含标签&lt;monthdate&gt;&lt;/amount&gt; 之间每次出现的数据。它应该如下所示:

XML值 --------- 2019-07-013021.190000000000 2019-07-0121310.386750000000

【问题讨论】:

您真的想要没有符号的输出 (&lt; &amp; &gt;)?还是这只是问题格式的问题? 嗨,是的,这是问题的格式,抱歉。我想要输出中的 (),因为我需要在仪表板报告的其他几个查询中使用临时表。 另外,您使用的是哪个 SQL 引擎? MS SQL Server、mysql、PostgreSQL,以及哪个版本? MS SQL SERVER 管理工作室 17 【参考方案1】:

我不确定你指的是哪一个。第一个将它们作为单独的 xml 行返回,另一个将它们作为类型数据行返回:

DECLARE @sample TABLE
(
    id INT IDENTITY,
    xmlSnippet VARCHAR(MAX)
);

INSERT @sample
(
    xmlSnippet
)
VALUES
('<monthdate>2019-07-01</monthdate>
<automitemno>302</automitemno>
<amount>1.190000000000</amount>
<currentamount>0.000000000000</currentamount>
<langitemno>1</langitemno>
<monthdate>2019-07-01</monthdate>
<automitemno>2131</automitemno>
<amount>0.386750000000</amount>
<currentamount>0.000000000000</currentamount>
<langitemno>1</langitemno>');


DECLARE @tempTable TABLE
(
    id INT,
    XMLValue XML
);

INSERT @tempTable
(
    id,
    XMLValue
)
SELECT id,
       CAST('<monthdate>' + value AS XML)
FROM @sample
    CROSS APPLY STRING_SPLIT(REPLACE(xmlSnippet, '<monthdate>', '&'), '&')
WHERE value <> '';
SELECT *
FROM @tempTable;

DECLARE @tempTable2 TABLE
(
    monthDate DATE,
    autoItemNo INT,
    amount MONEY,
    currentAmount MONEY
);

WITH myData (id, xmlRow)
AS (SELECT id,
           CAST('<monthdate>' + value AS XML)
    FROM @sample
        CROSS APPLY STRING_SPLIT(REPLACE(xmlSnippet, '<monthdate>', '&'), '&')
    WHERE value <> '')
INSERT @tempTable2
(
    monthDate,
    autoItemNo,
    amount,
    currentAmount
)
SELECT myData.xmlRow.value('/monthdate[1]', 'date'),
       myData.xmlRow.value('/automitemno[1]', 'int'),
       myData.xmlRow.value('/amount[1]', 'money'),
       myData.xmlRow.value('/currentamount[1]', 'money')
FROM myData;

SELECT *
FROM @tempTable2;

编辑:我添加了DBFiddle demo

【讨论】:

感谢以上内容,v 有帮助,只是一个额外的说明。我将如何从表和列中调用它,即..而不是将值设置为已知的 Nvarchar 值,如果要指定值在哪个表和列中并将结果插入到临时表中怎么办? 其实我是从表中调用的,@sample 是一个表变量,可能是一个真正的持久化表。 根据 TEMPORARY TABLE,只需将表变量 (@tempTable) 替换为像 #tempTable 这样的临时表。 嘿:我查询返回:无效的对象名称'STRING_SPLIT'??有任何想法吗?它识别出粉红色的命令但出错了? String_Split 是在 2016 版(兼容级别 130)中引入的。你用的是什么版本?检查我提供链接的 db fiddle 演示。【参考方案2】:

这里有一个解决方案,可以提供与所写内容完全相同的文本:

declare @xml as nvarchar(max)

set @xml = N'<monthdate>2019-07-01</monthdate>
<automitemno>302</automitemno>
<amount>1.190000000000</amount>
<currentamount>0.000000000000</currentamount>
<langitemno>1</langitemno>
<monthdate>2019-07-01</monthdate>
<automitemno>2131</automitemno>
<amount>0.386750000000</amount>
<currentamount>0.000000000000</currentamount>
<langitemno>1</langitemno>'


select replace(substring(a.value, charindex('<monthdate>',a.value)+11, charindex('</amount>', a.value)-16), char(10), '') as [XMLValue]

from string_split(replace(@xml, '</langitemno>', char(30)), char(30)) a

where a.value like '%<monthdate>%</amount>%'

DBFiddle

【讨论】:

以上是关于如何拆分包含 XML 字符串的 SQL 字段的主要内容,如果未能解决你的问题,请参考以下文章

如何避免作为 sql 查询输出的一部分返回的字符串值被拆分为 bash/shell 脚本中数组中的不同字段

在字段中拆分字符串并用作 sql 中的新列名

sql中如何判断字符串中含有特殊字符

如何在 BigQuery SQL 中将字符串列拆分为多行单个单词和单词对?

Java语句字符串如何拼接与拆分

sql SQL:使用XML拆分字符串