我如何分割一个string,所以我可以访问项目x?

使用SQL Server,如何分割一个string,以便可以访问项目x?

采取一个string“你好John Smith”。 我怎样才能分割string的空间和访问索引1应返回“约翰”的项目?

您可能会发现解决scheme在SQL用户定义函数parsing分隔符string有帮助(从代码项目 )。

你可以使用这个简单的逻辑:

Declare @products varchar(200) = '1|20|3|343|44|6|8765' Declare @individual varchar(20) = null WHILE LEN(@products) > 0 BEGIN IF PATINDEX('%|%', @products) > 0 BEGIN SET @individual = SUBSTRING(@products, 0, PATINDEX('%|%', @products)) SELECT @individual SET @products = SUBSTRING(@products, LEN(@individual + '|') + 1, LEN(@products)) END ELSE BEGIN SET @individual = @products SET @products = NULL SELECT @individual END END 

我不相信SQL Server有一个内置的拆分function,所以除UDF以外,我唯一知道的其他答案是劫持PARSENAME函数:

 SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 2) 

PARSENAME接受一个string并将其分割为句点字符。 它接受一个数字作为第二个参数,该数字指定要返回的string的哪一部分(从后到前工作)。

 SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 3) --return Hello 

明显的问题是当string已经包含一个句点。 我仍然认为使用UDF是最好的方法…任何其他的build议?

首先,创build一个函数(使用CTE,通用表expression式不需要临时表)

  create function dbo.SplitString ( @str nvarchar(4000), @separator char(1) ) returns table AS return ( with tokens(p, a, b) AS ( select 1, 1, charindex(@separator, @str) union all select p + 1, b + 1, charindex(@separator, @str, b + 1) from tokens where b > 0 ) select p-1 zeroBasedOccurance, substring( @str, a, case when b > 0 then ba ELSE 4000 end) AS s from tokens ) GO 

然后,将它用作任何表格(或修改它以适应您现有的存储过程),像这样。

 select s from dbo.SplitString('Hello John Smith', ' ') where zeroBasedOccurance=1 

更新

以前的版本会inputstring长度超过4000个字符。 这个版本照顾的限制:

 create function dbo.SplitString ( @str nvarchar(max), @separator char(1) ) returns table AS return ( with tokens(p, a, b) AS ( select cast(1 as bigint), cast(1 as bigint), charindex(@separator, @str) union all select p + 1, b + 1, charindex(@separator, @str, b + 1) from tokens where b > 0 ) select p-1 ItemIndex, substring( @str, a, case when b > 0 then ba ELSE LEN(@str) end) AS s from tokens ); GO 

用法保持不变。

这里的大多数解决scheme使用while循环或recursionCTE。 基于集合的方法将是优越的,我保证:

 CREATE FUNCTION [dbo].[SplitString] ( @List NVARCHAR(MAX), @Delim VARCHAR(255) ) RETURNS TABLE AS RETURN ( SELECT [Value] FROM ( SELECT [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number], CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number]))) FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name) FROM sys.all_objects) AS x WHERE Number <= LEN(@List) AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim ) AS y ); 

更多关于拆分函数的信息,为什么(以及certificate)while循环和recursionCTE不能缩放,以及更好的select,如果拆分来自应用层的string:

http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings

http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql

http://sqlblog.com/blogs/aaron_bertrand/archive/2010/07/07/splitting-a-list-of-integers-another-roundup.aspx

您可以利用数字表格来进行string分析。

创build一个物理数字表:

  create table dbo.Numbers (N int primary key); insert into dbo.Numbers select top 1000 row_number() over(order by number) from master..spt_values go 

用1000000行创buildtesting表

  create table #yak (i int identity(1,1) primary key, array varchar(50)) insert into #yak(array) select 'a,b,c' from dbo.Numbers n cross join dbo.Numbers nn go 

创build函数

  create function [dbo].[ufn_ParseArray] ( @Input nvarchar(4000), @Delimiter char(1) = ',', @BaseIdent int ) returns table as return ( select row_number() over (order by n asc) + (@BaseIdent - 1) [i], substring(@Input, n, charindex(@Delimiter, @Input + @Delimiter, n) - n) s from dbo.Numbers where n <= convert(int, len(@Input)) and substring(@Delimiter + @Input, n, 1) = @Delimiter ) go 

用法(在我的笔记本电脑上输出40米行数)

  select * from #yak cross apply dbo.ufn_ParseArray(array, ',', 1) 

清理

  drop table dbo.Numbers; drop function [dbo].[ufn_ParseArray] 

这里的性能并不奇妙,但是调用一百万行以上的函数并不是最好的主意。 如果执行一个string分割多行,我会避免该函数。

这是一个UDF,它将做到这一点。 它将返回一个分隔值的表,还没有尝试所有的场景,但你的例子工作正常。

 CREATE FUNCTION SplitString ( -- Add the parameters for the function here @myString varchar(500), @deliminator varchar(10) ) RETURNS @ReturnTable TABLE ( -- Add the column definitions for the TABLE variable here [id] [int] IDENTITY(1,1) NOT NULL, [part] [varchar](50) NULL ) AS BEGIN Declare @iSpaces int Declare @part varchar(50) --initialize spaces Select @iSpaces = charindex(@deliminator,@myString,0) While @iSpaces > 0 Begin Select @part = substring(@myString,0,charindex(@deliminator,@myString,0)) Insert Into @ReturnTable(part) Select @part Select @myString = substring(@mystring,charindex(@deliminator,@myString,0)+ len(@deliminator),len(@myString) - charindex(' ',@myString,0)) Select @iSpaces = charindex(@deliminator,@myString,0) end If len(@myString) > 0 Insert Into @ReturnTable Select @myString RETURN END GO 

你会这样称呼它:

 Select * From SplitString('Hello John Smith',' ') 

编辑:更新解决scheme来处理分隔符len> 1,如下所示:

 select * From SplitString('Hello**John**Smith','**') 

没有代码,但阅读关于这个权威性的文章。 其他答案中的所有解决scheme都是本文列出的解决scheme: SQL Server 2005及更高版本中的数组和列表

就个人而言,我经常使用数字表格解决scheme,因为它适合我所要做的…

在这里,我发布了一个简单的解决方法

 CREATE FUNCTION [dbo].[split]( @delimited NVARCHAR(MAX), @delimiter NVARCHAR(100) ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX)) AS BEGIN DECLARE @xml XML SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>' INSERT INTO @t(val) SELECT r.value('.','varchar(MAX)') as item FROM @xml.nodes('/t') as records(r) RETURN END 

执行像这样的function

  select * from dbo.split('Hello John Smith',' ') 

在我看来,你们是太复杂了。 只需创build一个CLR UDF并完成它。

 using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; using System.Collections.Generic; public partial class UserDefinedFunctions { [SqlFunction] public static SqlString SearchString(string Search) { List<string> SearchWords = new List<string>(); foreach (string s in Search.Split(new char[] { ' ' })) { if (!s.ToLower().Equals("or") && !s.ToLower().Equals("and")) { SearchWords.Add(s); } } return new SqlString(string.Join(" OR ", SearchWords.ToArray())); } }; 

怎么样使用stringvalues()语句?

 DECLARE @str varchar(max) SET @str = 'Hello John Smith' DECLARE @separator varchar(max) SET @separator = ' ' DECLARE @Splited TABLE(id int IDENTITY(1,1), item varchar(max)) SET @str = REPLACE(@str, @separator, '''),(''') SET @str = 'SELECT * FROM (VALUES(''' + @str + ''')) AS V(A)' INSERT INTO @Splited EXEC(@str) SELECT * FROM @Splited 

达到了结果集。

 id item 1 Hello 2 John 3 Smith 

我使用frederic的答案,但是这在SQL Server 2005中不起作用

我修改它,我使用selectunion all ,它的工作原理

 DECLARE @str varchar(max) SET @str = 'Hello John Smith how are you' DECLARE @separator varchar(max) SET @separator = ' ' DECLARE @Splited table(id int IDENTITY(1,1), item varchar(max)) SET @str = REPLACE(@str, @separator, ''' UNION ALL SELECT ''') SET @str = ' SELECT ''' + @str + ''' ' INSERT INTO @Splited EXEC(@str) SELECT * FROM @Splited 

结果集是:

 id item 1 Hello 2 John 3 Smith 4 how 5 are 6 you 

问题不是关于string拆分方法 ,而是关于如何获得第n个元素

这里的所有答案正在使用recursion, CTE ,多个CHARINDEXREVERSEPATINDEX ,发明函数,调用CLR方法,数字表, CROSS APPLY等进行某种types的string拆分…大多数答案都包含许多代码行。

但是,如果你真的只想得到第n个元素 ,就可以做到真正的一行 ,没有UDF,甚至没有子select…作为额外的好处: types安全

获取由空间分隔的第2部分:

 DECLARE @input NVARCHAR(100)=N'part1 part2 part3'; SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)') 

当然你可以使用variables来定界和定位(使用sql:column直接从查询的值中获取位置):

 DECLARE @dlmt NVARCHAR(10)=N' '; DECLARE @pos INT = 2; SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)') 

如果你的string可能包含禁止的字符 (尤其是&><之一),你仍然可以这样做。 首先在string上使用FOR XML PATH来隐式地用拟合转义序列replace所有禁止的字符。

这是一个非常特殊的情况,如果 – 另外 – 你的分隔符是分号 。 在这种情况下,首先将分隔符replace为“#DLMT#”,并最终将其replace为XML标签:

 SET @input=N'Some <, > and &;Other äöü@€;One more'; SET @dlmt=N';'; SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)'); 

这种模式工作正常,你可以概括

 Convert(xml,'<n>'+Replace(FIELD,'.','</n><n>')+'</n>').value('(/n[INDEX])','TYPE') ^^^^^ ^^^^^ ^^^^ 

注意FIELDINDEXTYPE

让一些带有标识符的表

 sys.message.1234.warning.A45 sys.message.1235.error.O98 .... 

然后,你可以写

 SELECT Source = q.value('(/n[1])', 'varchar(10)'), RecordType = q.value('(/n[2])', 'varchar(20)'), RecordNumber = q.value('(/n[3])', 'int'), Status = q.value('(/n[4])', 'varchar(5)') FROM ( SELECT q = Convert(xml,'<n>'+Replace(fieldName,'.','</n><n>')+'</n>') FROM some_TABLE ) Q 

拆分和铸造所有部件。

我在网上寻找解决scheme,下面的工作对我来说。 Ref 。

你可以这样调用函数:

 SELECT * FROM dbo.split('ram shyam hari gopal',' ') 

 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1)) RETURNS @temptable TABLE (items VARCHAR(8000)) AS BEGIN DECLARE @idx INT DECLARE @slice VARCHAR(8000) SELECT @idx = 1 IF len(@String)<1 OR @String IS NULL RETURN WHILE @idx!= 0 BEGIN SET @idx = charindex(@Delimiter,@String) IF @idx!=0 SET @slice = LEFT(@String,@idx - 1) ELSE SET @slice = @String IF(len(@slice)>0) INSERT INTO @temptable(Items) VALUES(@slice) SET @String = RIGHT(@String,len(@String) - @idx) IF len(@String) = 0 break END RETURN END 

还有另一个通过delimeter函数得到string的第n部分:

 create function GetStringPartByDelimeter ( @value as nvarchar(max), @delimeter as nvarchar(max), @position as int ) returns NVARCHAR(MAX) AS BEGIN declare @startPos as int declare @endPos as int set @endPos = -1 while (@position > 0 and @endPos != 0) begin set @startPos = @endPos + 1 set @endPos = charindex(@delimeter, @value, @startPos) if(@position = 1) begin if(@endPos = 0) set @endPos = len(@value) + 1 return substring(@value, @startPos, @endPos - @startPos) end set @position = @position - 1 end return null end 

和用法:

 select dbo.GetStringPartByDelimeter ('a;b;c;d;e', ';', 3) 

它返回:

 c 

尝试这个:

 CREATE function [SplitWordList] ( @list varchar(8000) ) returns @t table ( Word varchar(50) not null, Position int identity(1,1) not null ) as begin declare @pos int, @lpos int, @item varchar(100), @ignore varchar(100), @dl int, @a1 int, @a2 int, @z1 int, @z2 int, @n1 int, @n2 int, @c varchar(1), @a smallint select @a1 = ascii('a'), @a2 = ascii('A'), @z1 = ascii('z'), @z2 = ascii('Z'), @n1 = ascii('0'), @n2 = ascii('9') set @ignore = '''"' set @pos = 1 set @dl = datalength(@list) set @lpos = 1 set @item = '' while (@pos <= @dl) begin set @c = substring(@list, @pos, 1) if (@ignore not like '%' + @c + '%') begin set @a = ascii(@c) if ((@a >= @a1) and (@a <= @z1)) or ((@a >= @a2) and (@a <= @z2)) or ((@a >= @n1) and (@a <= @n2)) begin set @item = @item + @c end else if (@item > '') begin insert into @t values (@item) set @item = '' end end set @pos = @pos + 1 end if (@item > '') begin insert into @t values (@item) end return end 

像这样testing它:

 select * from SplitWordList('Hello John Smith') 

以下示例使用recursionCTE

更新 18.09.2013

 CREATE FUNCTION dbo.SplitStrings_CTE(@List nvarchar(max), @Delimiter nvarchar(1)) RETURNS @returns TABLE (val nvarchar(max), [level] int, PRIMARY KEY CLUSTERED([level])) AS BEGIN ;WITH cte AS ( SELECT SUBSTRING(@List, 0, CHARINDEX(@Delimiter, @List + @Delimiter)) AS val, CAST(STUFF(@List + @Delimiter, 1, CHARINDEX(@Delimiter, @List + @Delimiter), '') AS nvarchar(max)) AS stval, 1 AS [level] UNION ALL SELECT SUBSTRING(stval, 0, CHARINDEX(@Delimiter, stval)), CAST(STUFF(stval, 1, CHARINDEX(@Delimiter, stval), '') AS nvarchar(max)), [level] + 1 FROM cte WHERE stval != '' ) INSERT @returns SELECT REPLACE(val, ' ','' ) AS val, [level] FROM cte WHERE val > '' RETURN END 

演示SQLFiddle

 Alter Function dbo.fn_Split ( @Expression nvarchar(max), @Delimiter nvarchar(20) = ',', @Qualifier char(1) = Null ) RETURNS @Results TABLE (id int IDENTITY(1,1), value nvarchar(max)) AS BEGIN /* USAGE Select * From dbo.fn_Split('apple pear grape banana orange honeydew cantalope 3 2 1 4', ' ', Null) Select * From dbo.fn_Split('1,abc,"Doe, John",4', ',', '"') Select * From dbo.fn_Split('Hello 0,"&""&&&&', ',', '"') */ -- Declare Variables DECLARE @X xml, @Temp nvarchar(max), @Temp2 nvarchar(max), @Start int, @End int -- HTML Encode @Expression Select @Expression = (Select @Expression For XML Path('')) -- Find all occurences of @Delimiter within @Qualifier and replace with 

***

While PATINDEX('%' + @Qualifier + '%', @Expression) > 0 AND Len(IsNull(@Qualifier, '')) > 0 BEGIN Select — Starting character position of @Qualifier @Start = PATINDEX('%' + @Qualifier + '%', @Expression), — @Expression starting at the @Start position @Temp = SubString(@Expression, @Start + 1, LEN(@Expression)-@Start+1), — Next position of @Qualifier within @Expression @End = PATINDEX('%' + @Qualifier + '%', @Temp) – 1, — The part of Expression found between the @Qualifiers @Temp2 = Case When @End < 0 Then @Temp Else Left(@Temp, @End) End, — New @Expression @Expression = REPLACE(@Expression, @Qualifier + @Temp2 + Case When @End < 0 Then '' Else @Qualifier End, Replace(@Temp2, @Delimiter, '

***

') ) END — Replace all occurences of @Delimiter within @Expression with '</fn_Split>&ltfn_Split>' — And convert it to XML so we can select from it SET @X = Cast('&ltfn_Split>' + Replace(@Expression, @Delimiter, '</fn_Split>&ltfn_Split>') + '</fn_Split>' as xml) — Insert into our returnable table replacing '

***

' back to @Delimiter INSERT @Results SELECT "Value" = LTRIM(RTrim(Replace(C.value('.', 'nvarchar(max)'), '

***

', @Delimiter))) FROM @X.nodes('fn_Split') as X(C) — Return our temp table RETURN END

我知道这是一个古老的问题,但我认为有人可以从我的解决scheme中受益。

 select SUBSTRING(column_name,1,CHARINDEX(' ',column_name,1)-1) ,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)) ,1 ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)-1) ,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)) ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)+1 ,LEN(column_name)) from table_name 

SQL FIDDLE

优点:

  • 它将所有3个子string分隔符用“'分开。
  • 一定不要使用while循环,因为它会降低性能。
  • 不需要枢轴,因为所有的结果子string将显示在一行中

限制:

  • 你必须知道总数。 (子串)。

注意 :解决scheme可以将子串提供给N.

为了克服限制,我们可以使用下面的参考

但是,上述解决scheme再次不能用在表格中(我无法使用它)。

再次,我希望这个解决scheme可以帮助一个人。

更新:如果logging> 50000,则不build议使用LOOPS ,否则会降低性能

几乎所有其他的答案分裂代码正在取代被拆分的string,浪费CPU周期,并执行不必要的内存分配。

我介绍了一个更好的方法来做一个string拆分: http : //www.digitalruby.com/split-string-sql-server/

这里是代码:

 SET NOCOUNT ON -- You will want to change nvarchar(MAX) to nvarchar(50), varchar(50) or whatever matches exactly with the string column you will be searching against DECLARE @SplitStringTable TABLE (Value nvarchar(MAX) NOT NULL) DECLARE @StringToSplit nvarchar(MAX) = 'your|string|to|split|here' DECLARE @SplitEndPos int DECLARE @SplitValue nvarchar(MAX) DECLARE @SplitDelim nvarchar(1) = '|' DECLARE @SplitStartPos int = 1 SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos) WHILE @SplitEndPos > 0 BEGIN SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, (@SplitEndPos - @SplitStartPos)) INSERT @SplitStringTable (Value) VALUES (@SplitValue) SET @SplitStartPos = @SplitEndPos + 1 SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos) END SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, 2147483647) INSERT @SplitStringTable (Value) VALUES(@SplitValue) SET NOCOUNT OFF -- You can select or join with the values in @SplitStringTable at this point. 

使用TVF和recursionCTE纯集合解决scheme。 您可以JOINAPPLY此function到任何数据集。

 create function [dbo].[SplitStringToResultSet] (@value varchar(max), @separator char(1)) returns table as return with r as ( select value, cast(null as varchar(max)) [x], -1 [no] from (select rtrim(cast(@value as varchar(max))) [value]) as j union all select right(value, len(value)-case charindex(@separator, value) when 0 then len(value) else charindex(@separator, value) end) [value] , left(r.[value], case charindex(@separator, r.value) when 0 then len(r.value) else abs(charindex(@separator, r.[value])-1) end ) [x] , [no] + 1 [no] from r where value > '') select ltrim(x) [value], [no] [index] from r where x is not null; go 

用法:

 select * from [dbo].[SplitStringToResultSet]('Hello John Smith', ' ') where [index] = 1; 

结果:

 value index ------------- John 1 

您可以在不需要函数的情况下在SQL中拆分string:

 DECLARE @bla varchar(MAX) SET @bla = 'BED40DFC-F468-46DD-8017-00EF2FA3E4A4,64B59FC5-3F4D-4B0E-9A48-01F3D4F220B0,A611A108-97CA-42F3-A2E1-057165339719,E72D95EA-578F-45FC-88E5-075F66FD726C' -- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes SELECT x.XmlCol.value('.', 'varchar(36)') AS val FROM ( SELECT CAST('<e>' + REPLACE(@bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml ) AS b CROSS APPLY b.RawXml.nodes('e') x(XmlCol); 

如果您需要支持任意string(使用xml特殊字符)

 DECLARE @bla NVARCHAR(MAX) SET @bla = '<html>unsafe & safe Utf8CharsDon''tGetEncoded ÄöÜ - "Conex"<html>,Barnes & Noble,abc,def,ghi' -- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes SELECT x.XmlCol.value('.', 'nvarchar(MAX)') AS val FROM ( SELECT CAST('<e>' + REPLACE((SELECT @bla FOR XML PATH('')), ',', '</e><e>') + '</e>' AS xml) AS RawXml ) AS b CROSS APPLY b.RawXml.nodes('e') x(XmlCol); 

SQL Server 2016开始我们string_split

 DECLARE @string varchar(100) = 'Richard, Mike, Mark' SELECT value FROM string_split(@string, ',') 

那么,我不是那么简单,但这里是我用来将逗号分隔的inputvariables分割成单个值的代码,并将其放入一个表variables。 我相信你可以稍微修改这个基于空间分割,然后对该表variables做一个基本的SELECT查询来获得你的结果。

 -- Create temporary table to parse the list of accounting cycles. DECLARE @tblAccountingCycles table ( AccountingCycle varchar(10) ) DECLARE @vchAccountingCycle varchar(10) DECLARE @intPosition int SET @vchAccountingCycleIDs = LTRIM(RTRIM(@vchAccountingCycleIDs)) + ',' SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1) IF REPLACE(@vchAccountingCycleIDs, ',', '') <> '' BEGIN WHILE @intPosition > 0 BEGIN SET @vchAccountingCycle = LTRIM(RTRIM(LEFT(@vchAccountingCycleIDs, @intPosition - 1))) IF @vchAccountingCycle <> '' BEGIN INSERT INTO @tblAccountingCycles (AccountingCycle) VALUES (@vchAccountingCycle) END SET @vchAccountingCycleIDs = RIGHT(@vchAccountingCycleIDs, LEN(@vchAccountingCycleIDs) - @intPosition) SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1) END END 

这个概念几乎是一样的。 另一种select是利用SQL Server 2005本身的.NET兼容性。 你基本上可以自己写一个简单的.NET方法来分割string,然后将其作为存储过程/函数公开。

这是我为了获得一个string中的特定标记而做的事情。 (在MSSQL 2008中testing)

首先,创build以下function:(发现在这里 :

 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,tN,1) = @Delimiter OR tN = 0)) SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)) FROM cteStart s; 

 create FUNCTION dbo.getToken ( @List NVARCHAR(MAX), @Delimiter NVARCHAR(255), @Pos int ) RETURNS varchar(max) as begin declare @returnValue varchar(max); select @returnValue = tbl.Item from ( select ROW_NUMBER() over (order by (select null)) as id, * from dbo.SplitStrings_Moden(@List, @Delimiter) ) as tbl where tbl.id = @Pos return @returnValue end 

then you can use it like that:

 select dbo.getToken('1111_2222_3333_', '_', 1) 

which return 1111

Recursive CTE solution with server pain, test it

MS SQL Server 2008 Schema Setup :

 create table Course( Courses varchar(100) ); insert into Course values ('Hello John Smith'); 

Query 1 :

 with cte as ( select left( Courses, charindex( ' ' , Courses) ) as a_l, cast( substring( Courses, charindex( ' ' , Courses) + 1 , len(Courses ) ) + ' ' as varchar(100) ) as a_r, Courses as a, 0 as n from Course t union all select left(a_r, charindex( ' ' , a_r) ) as a_l, substring( a_r, charindex( ' ' , a_r) + 1 , len(a_R ) ) as a_r, cte.a, cte.n + 1 as n from Course t inner join cte on t.Courses = cte.a and len( a_r ) > 0 ) select a_l, n from cte --where N = 1 

Results :

 | A_L | N | |--------|---| | Hello | 0 | | John | 1 | | Smith | 2 | 

while similar to the xml based answer by josejuan, i found that processing the xml path only once, then pivoting was moderately more efficient:

 select ID, [3] as PathProvidingID, [4] as PathProvider, [5] as ComponentProvidingID, [6] as ComponentProviding, [7] as InputRecievingID, [8] as InputRecieving, [9] as RowsPassed, [10] as InputRecieving2 from ( select id,message,d.* from sysssislog cross apply ( SELECT Item = yivalue('(./text())[1]', 'varchar(200)'), row_number() over(order by yi) as rn FROM ( SELECT x = CONVERT(XML, '<i>' + REPLACE(Message, ':', '</i><i>') + '</i>').query('.') ) AS a CROSS APPLY x.nodes('i') AS y(i) ) d WHERE event = 'OnPipelineRowsSent' ) as tokens pivot ( max(item) for [rn] in ([3],[4],[5],[6],[7],[8],[9],[10]) ) as data 

ran in 8:30

 select id, tokens.value('(/n[3])', 'varchar(100)')as PathProvidingID, tokens.value('(/n[4])', 'varchar(100)') as PathProvider, tokens.value('(/n[5])', 'varchar(100)') as ComponentProvidingID, tokens.value('(/n[6])', 'varchar(100)') as ComponentProviding, tokens.value('(/n[7])', 'varchar(100)') as InputRecievingID, tokens.value('(/n[8])', 'varchar(100)') as InputRecieving, tokens.value('(/n[9])', 'varchar(100)') as RowsPassed from ( select id, Convert(xml,'<n>'+Replace(message,'.','</n><n>')+'</n>') tokens from sysssislog WHERE event = 'OnPipelineRowsSent' ) as data 

ran in 9:20

 CREATE FUNCTION [dbo].[fnSplitString] ( @string NVARCHAR(MAX), @delimiter CHAR(1) ) RETURNS @output TABLE(splitdata NVARCHAR(MAX) ) BEGIN DECLARE @start INT, @end INT SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) WHILE @start < LEN(@string) + 1 BEGIN IF @end = 0 SET @end = LEN(@string) + 1 INSERT INTO @output (splitdata) VALUES(SUBSTRING(@string, @start, @end - @start)) SET @start = @end + 1 SET @end = CHARINDEX(@delimiter, @string, @start) END RETURN END 

AND USE IT

 select *from dbo.fnSplitString('Querying SQL Server','') 

if anyone wants to get only one part of the seperatured text can use this

select * from fromSplitStringSep('Word1 wordr2 word3',' ')

 CREATE function [dbo].[SplitStringSep] ( @str nvarchar(4000), @separator char(1) ) returns table AS return ( with tokens(p, a, b) AS ( select 1, 1, charindex(@separator, @str) union all select p + 1, b + 1, charindex(@separator, @str, b + 1) from tokens where b > 0 ) select p-1 zeroBasedOccurance, substring( @str, a, case when b > 0 then ba ELSE 4000 end) AS s from tokens ) 

I devoloped this,

 declare @x nvarchar(Max) = 'ali.veli.deli.'; declare @item nvarchar(Max); declare @splitter char='.'; while CHARINDEX(@splitter,@x) != 0 begin set @item = LEFT(@x,CHARINDEX(@splitter,@x)) set @x = RIGHT(@x,len(@x)-len(@item) ) select @item as item, @x as x; end 

the only attention you should is dot '.' that end of the @x is always should be there.