在 SQL Server 中将数据转换为 XML 时出错

Posted

技术标签:

【中文标题】在 SQL Server 中将数据转换为 XML 时出错【英文标题】:Error when converting data to XML in SQL Server 【发布时间】:2019-09-13 13:39:49 【问题描述】:

我需要检索 View 表中逗号分隔字符串的位置 10 中的内容。

Row 1    N,l,S,T,A,,<all>,,N,A,N,N,N,Y,Y,,Y,Y,Y,,AA,SA,Enterprise, 
Row 2    M,,A,S,AS,SS,AS,N,N,N,N,Y,Y,Y,ENTERPRISE,S,,A
Row 3    L,,A,D,S,A,A,AA,Y,Y,Y,YNN,N,N,N,N,A,AA,AD,D,D

Div1 是我的列的名称,Div2 是结果列的名称。我使用以下代码:

SELECT TOP (2000) 
    [Id],
    CONVERT(XML,'<x>' + REPLACE(REPLACE(REPLACE(Div1, '>', ''), '<', ''), ',', '</x <x>') + '</x>').value('/x[10]', 'VARCHAR(MAX)') [Div2], 
    Div1
FROM 
    [dbo].[database]

我使用字符类型VARCHAR(MAX),因为这是我数据库中 Div1 的类型。如果我运行的行数少于 20000,则该代码有效。但是我使用的数据集有超过 100,000 行。如果我运行整个数据,它会停止并出现以下错误:

消息 9421,第 16 级,状态 1,第 1 行。 XML解析:第1行,字符218,非法名称字符

有没有办法解决这个问题?

【问题讨论】:

要检索逗号分隔字符串的位置 10 中的内容,您不需要将字符串转换为 xml。您可以找到大量 SQL 示例来将 csv 字符串转换为结果集。 您的 SQL Server 版本是多少? 谢谢,我的 SQL Server Management Studio 版本是 15.0.18142.0 【参考方案1】:

XML 具有 CDATA[] 部分,无需解析即可按原样处理内容。不需要多个 REPLACE() 函数调用。看看吧。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE  (ID INT IDENTITY(1,1) PRIMARY KEY, Div1 VARCHAR(MAX));
INSERT INTO @tbl (Div1)
VALUES
('N,l,S,T,A,,<all>,,N,A,N,N,N,Y,Y,,Y,Y,Y,,AA,SA,Enterprise')
, ('M,,A,S,AS,SS,AS,N,N,N,N,Y,Y,Y,ENTERPRISE,S,,A')
, ('L,,A,D,S,A,A,AA,Y,Y,Y,YNN,N,N,N,N,A,AA,AD,D,D');
-- DDL and sample data population, end

SELECT [Id],
    CAST('<x><![CDATA[' + REPLACE(Div1, ',', ']]></x><x><![CDATA[') + ']]></x>' AS XML).value('(/x/text())[10]', 'VARCHAR(MAX)') [Div2], 
    Div1
FROM @tbl;

【讨论】:

好答案,我这边+1。 它在 value() 处略有变化时起作用。由于某种原因,如果我改变了位置,则值不正确。我的字符串很长,这只是一个摘录。看:SELECT [LacNo], CAST('' AS XML).value('(/x)[10]', 'VARCHAR(MAX)') [Div2], Div1 FROM dbo.database;【参考方案2】:

您可以创建一个函数来拆分字符串,如下所示:

CREATE FUNCTION dbo.split_delimited_string
(
    @list varchar(max),
    @delimiter varchar(5)
)  
RETURNS @items TABLE 
(
    pos_id int identity(1,1),
    item varchar(255)
) 
AS  
BEGIN 
    DECLARE @pos int, @delimiter_len tinyint;
    SET @pos = CHARINDEX(@delimiter,@list);
    SET @delimiter_len=LEN(@delimiter);
    WHILE (@pos>0)
    BEGIN
        INSERT INTO @items (item)
        SELECT LEFT(@list,@pos - 1)

        SET @list = RIGHT(@list,LEN(@list) - @pos - @delimiter_len + 1);
        SET @pos = CHARINDEX(@delimiter,@list);
    END 
    IF @list<>N''
    BEGIN
        INSERT INTO @items (item)
        SELECT @list;
    END 
    RETURN;
END

以下查询将返回第 10 位的内容:

SELECT
    t.[Id],
    l.item AS Div2
    t.Div1
FROM [dbo].[database] t
CROSS APPLY dbo.split_delimited_string(t.Div1,',') l
WHERE l.pos_id = 10;

【讨论】:

以上是关于在 SQL Server 中将数据转换为 XML 时出错的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 2008 中将 NVARCHAR 转换为 INT 数据类型

在sql server中将xml列值编码为xml

如何在 SQL Server 中将字符串转换为日期时间?

在 SQL Server 数据库中将长日期时间转换为实际日期时间的最佳方法是啥?

如何在 SQL Server 中将行动态转换为列

在 PHP Laravel 中的 SQL Server 中将字符串转换为日期数据类型