Sql server SQL Server 2008拆分字符串由于使用了符号AND而失败
我创建了一个存储过程,试图复制SQL Server 2016中的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
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
来解决这类问题…@MatBaillieFOR XML
用于字符串聚合。在本例中,只有一个字符串通过将分隔符替换为'
转换为XML。这里唯一的解决方案是转义无效字符将所有'&
'替换为'&;'代码>,就像正常使用html/xml一样?然后,一旦拆分,再将其转换回来?这种“技巧”的更健壮的实现使用FOR XML
来解决这类问题…@MatBaillieFOR 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,'&','&')
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