Sql server SQL Server 2008拆分字符串由于使用了符号AND而失败

Sql server SQL Server 2008拆分字符串由于使用了符号AND而失败,sql-server,tsql,Sql Server,Tsql,我创建了一个存储过程,试图复制SQL Server 2016中的split_string函数 到目前为止,我已经做到了: CREATE FUNCTION MySplit (@delimited NVARCHAR(MAX), @delimiter NVARCHAR(100)) RETURNS @t TABLE ( -- Id column can be commented out, not required for SQL splitting string id INT IDENTI

我创建了一个存储过程,试图复制SQL Server 2016中的
split_string
函数

到目前为止,我已经做到了:

CREATE FUNCTION MySplit
    (@delimited NVARCHAR(MAX), @delimiter NVARCHAR(100)) 
RETURNS @t TABLE
(
-- Id column can be commented out, not required for SQL splitting string
  id INT IDENTITY(1,1), -- I use this column for numbering split parts
  val NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @xml XML
    SET @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'

    INSERT INTO @t(val)
        SELECT
            r.value('.','varchar(max)') AS item
        FROM
            @xml.nodes('//root/r') AS records(r)

    RETURN
END
GO
可以,但是

select * 
from MySplit('Test1 & Test4,Test2,Test3', ',') 
没有。它失败了

XML解析:第1行,字符17,非法名称字符

我做错了什么

更新

首先,感谢@marcs,让我知道我在写这个问题时的错误

其次,感谢下面所有的帮助,特别是@PanagiotisKanavos和@MatBailie

由于这是用于将数据从旧系统迁移到新系统的一次性代码,所以我选择使用@MatBailie解决方案,速度快且非常脏,但也非常适合此任务


不过,在将来,我将继续使用@PanagiotisKanavos解决方案。

编辑您的函数,并将所有
&
替换为
&

这将删除错误。这是因为XML无法解析
&
,因为它是一个内置标记。

编辑您的函数并将所有
&
替换为
&

这将删除错误。这是因为XML无法解析
&
,因为它是一个内置标记。

首先,SQL Server 2016引入了TVF。您可以将
交叉应用字符串_-SPLIT(该字段,“,”)作为项目写入

在以前的版本中,您仍然需要创建自定义拆分函数。最快的解决方案是使用SQLCLR函数

在某些情况下,第二快的是您使用的- 将文本转换为XML并选择节点。这种拆分技术的一个众所周知的问题是,非法XML字符会破坏它,正如您所发现的。这就是为什么Aaron Bertrand不认为这是一个通用的分裂器。< /P> 您可以用编码值替换无效字符,例如
&
替换为
&
也许您应该研究不同的技术,例如调制解调器功能,在许多情况下,它可以更快:

CREATE FUNCTION dbo.SplitStrings_Moden
(
   @List NVARCHAR(MAX),
   @Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
  WITH E1(N)        AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
       E2(N)        AS (SELECT 1 FROM E1 a, E1 b),
       E4(N)        AS (SELECT 1 FROM E2 a, E2 b),
       E42(N)       AS (SELECT 1 FROM E4 a, E2 b),
       cteTally(N)  AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
                         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
       cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
                         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
  SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
    FROM cteStart s;
我个人创建并使用了SQLCLR UDF

另一种选择是避免完全拆分,并将表值参数从客户端传递到服务器。或者使用像Dapper这样的microORM,它可以从值列表中构造
IN(…)
子句,例如:

var products=connection.Query<Product>("select * from products where id in @ids",new {ids=myIdArray});

首先,SQL Server 2016引入了TVF。您可以将
交叉应用字符串_-SPLIT(该字段,“,”)作为项目写入

在以前的版本中,您仍然需要创建自定义拆分函数。最快的解决方案是使用SQLCLR函数

在某些情况下,第二快的是您使用的- 将文本转换为XML并选择节点。这种拆分技术的一个众所周知的问题是,非法XML字符会破坏它,正如您所发现的。这就是为什么Aaron Bertrand不认为这是一个通用的分裂器。< /P> 您可以用编码值替换无效字符,例如
&
替换为
&
也许您应该研究不同的技术,例如调制解调器功能,在许多情况下,它可以更快:

CREATE FUNCTION dbo.SplitStrings_Moden
(
   @List NVARCHAR(MAX),
   @Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
  WITH E1(N)        AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
       E2(N)        AS (SELECT 1 FROM E1 a, E1 b),
       E4(N)        AS (SELECT 1 FROM E2 a, E2 b),
       E42(N)       AS (SELECT 1 FROM E4 a, E2 b),
       cteTally(N)  AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
                         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
       cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
                         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
  SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
    FROM cteStart s;
我个人创建并使用了SQLCLR UDF

另一种选择是避免完全拆分,并将表值参数从客户端传递到服务器。或者使用像Dapper这样的microORM,它可以从值列表中构造
IN(…)
子句,例如:

var products=connection.Query<Product>("select * from products where id in @ids",new {ids=myIdArray});
创建函数[dbo]。[split\u stringss](
@分隔的NVARCHAR(最大值),
@分隔符NVARCHAR(100)
)返回@t表(id INT IDENTITY(1,1),val NVARCHAR(MAX))
作为
开始
声明@xml
声明@var NVARCHAR(最大值)
声明@var1 NVARCHAR(最大值)
设置@var1=Replace(@delimited,&,'&;'))
设置@xml=N''+替换(@var1,@delimiter'')+''
插入@t(val)
选择r.value('.','varchar(MAX')作为项目
从@xml.nodes('/t')作为记录(r)
返回
结束
创建函数[dbo]。[split\u stringss](
@分隔的NVARCHAR(最大值),
@分隔符NVARCHAR(100)
)返回@t表(id INT IDENTITY(1,1),val NVARCHAR(MAX))
作为
开始
声明@xml
声明@var NVARCHAR(最大值)
声明@var1 NVARCHAR(最大值)
设置@var1=Replace(@delimited,&,'&;'))
设置@xml=N''+替换(@var1,@delimiter'')+''
插入@t(val)
选择r.value('.','varchar(MAX')作为项目
从@xml.nodes('/t')作为记录(r)
返回
结束

将所有
'和
'替换为
'&;',就像正常使用html/xml一样?然后,一旦拆分,再将其转换回来?这种“技巧”的更健壮的实现使用
FOR XML
来解决这类问题…@MatBaillie
FOR XML
用于字符串聚合。在本例中,只有一个字符串通过将分隔符替换为
'
转换为XML。这里唯一的解决方案是转义无效字符将所有
'&
'替换为
'&;',就像正常使用html/xml一样?然后,一旦拆分,再将其转换回来?这种“技巧”的更健壮的实现使用
FOR XML
来解决这类问题…@MatBaillie
FOR XML
用于字符串聚合。在本例中,只有一个字符串通过将分隔符替换为
'
转换为XML。这里唯一的解决办法是避开无效字符。虽然这个代码片段可以解决这个问题,但它确实有助于提高文章的质量。请记住,您将在将来回答读者的问题,而这些人可能不知道您的代码建议的原因。虽然此代码片段可以解决问题,但确实有助于提高您文章的质量。请记住,您将在将来回答读者的问题,这些人可能不知道您的代码建议的原因。
Create FUNCTION [dbo].[split_stringss](
          @delimited NVARCHAR(MAX),
          @delimiter NVARCHAR(100)
        ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
  DECLARE @xml XML
    DECLARE @var NVARCHAR(MAX)
  DECLARE @var1 NVARCHAR(MAX)
   set @var1 =  Replace(@delimited,'&','&amp;') 
  SET @xml = N'<t>' + REPLACE(@var1,@delimiter,'</t><t>') + '</t>'  
  INSERT INTO @t(val)
  SELECT  r.value('.','varchar(MAX)') as item
  FROM  @xml.nodes('/t') as records(r)
  RETURN
END