7

我有以下Split功能,

ALTER FUNCTION [dbo].[Split](@String varchar(8000), @Delimiter char(1))     
                returns @temptable TABLE (items varchar(8000))     
            as     
            begin
                set @String = RTRIM(LTRIM(@String))
                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

当我写作时,

SELECT Items 
FROM Split('around the home,clean and protect,soaps and air fresheners,air fresheners',',')

这会给我,

air fresheners
around the home
clean and protect
soaps and air fresheners

我需要维持秩序。

4

5 回答 5

7

一个更简单的功能:

CREATE FUNCTION dbo.SplitStrings_Ordered
(
    @List       nvarchar(MAX),
    @Delimiter  nvarchar(255)
)
RETURNS TABLE
AS
RETURN 
(
  SELECT [Index] = CHARINDEX(@Delimiter, @List + @Delimiter, Number),
         Item = SUBSTRING(@List, Number, CHARINDEX(@Delimiter, 
                @List + @Delimiter, Number) - Number)
    FROM 
    (
      SELECT ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects
    ) AS n(Number)
    WHERE Number <= CONVERT(INT, LEN(@List))
    AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
);
GO

示例用法:

DECLARE @s nvarchar(MAX) = N',around the home,clean and protect,soaps and air'
  + ' fresheners,air fresheners';

SELECT Item FROM dbo.SplitStrings_Ordered(@s, N',') ORDER BY [Index];

或者从按输入排序的表中返回订单:

SELECT o.OrderID
  FROM dbo.Orders AS o
  INNER JOIN dbo.SplitStrings_Ordered('123,789,456') AS f
  ON o.OrderID = CONVERT(int, f.Item)
  ORDER BY f.[Index];
于 2013-10-06T14:23:47.523 回答
1

您的函数将需要设置一个订单列(本示例中的 seq):

ALTER FUNCTION [dbo].[Split](@String varchar(8000), @Delimiter char(1))     
            returns @temptable TABLE (seq int, items varchar(8000))     
        as     
        begin
            set @String = RTRIM(LTRIM(@String))
            declare @idx int     
            declare @seq int
            declare @slice varchar(8000)     

            set @seq=1

            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)
                begin
                    set @seq = @seq + 1
                    insert into @temptable(seq, Items) values(@seq,@slice)     
                end

                set @String = right(@String,len(@String) - @idx)     
                if len(@String) = 0 break     
            end 
        return     
        end
GO
SELECT * FROM Split('around the home,clean and protect,soaps and air fresheners,air fresheners',',') order by seq 
于 2013-10-06T14:18:24.397 回答
1
declare @Version nvarchar(3000)
declare @Delimiter char(1) = ','
declare @result nvarchar(3000)
set @Version = 'Terça-feira, Quarta-feira, Sexta-feira, Segunda-feira';

with V as (select value v, Row_Number() over (order by (select 0)) n 
    from String_Split(@Version, @Delimiter)
)
    SELECT @result = STUFF((SELECT ', ' + RTRIM(LTRIM(v))
      FROM V
      ORDER BY CASE RTRIM(LTRIM(v))
            WHEN 'Segunda-feira' then 1 
            WHEN 'Terça-feira' then 2
            WHEN 'Quarta-feira' then 3 
            WHEN 'Quinta-feira' then 4 
            WHEN 'Sexta-feira' then 5
           END FOR XML PATH('')), 1, LEN(@Delimiter), '')
PRINT @result
于 2020-03-31T13:53:39.150 回答
0

当您的字符串有 1000 个或更多值要拆分时,这将是一个更快的解决方案。对于表值函数,要进行任何排序,您必须在使用位置应用“ORDER BY”。这是因为没有“ORDER BY”的表中的“SELECT”按照惯例没有任何排序。

CREATE FUNCTION [dbo].[Split]
( 
    @String VARCHAR(max), 
    @Delimiter VARCHAR(max)
) 
RETURNS @Data TABLE 
(
    [Order] INT IDENTITY(1,1), 
    [Value] VARCHAR(max)
)
AS
BEGIN 
    DECLARE @x XML = cast('<i>' + replace(@String, @Delimiter, '</i><i>') + '</i>' AS XML)
    INSERT INTO @Data 
    SELECT v.value('.', 'varchar(max)') FROM @x.nodes('i') AS x(v)
    RETURN 
END
GO
于 2020-03-31T15:24:48.270 回答
-1

如果您可以遵守 SQL Server 的兼容级别 130,则可以使用该String_Split()功能。

使用此函数和 Row_Number() 函数,您可以返回包含原始序列的表。例如:

declare @Version nvarchar(128)
set @Version = '1.2.3';

with V as (select value v, Row_Number() over (order by (select 0)) n 
    from String_Split(@Version, '.')
)
    select
        (select v from V where n = 1) Major,
        (select v from V where n = 2) Minor,
        (select v from V where n = 3) Revision

请注意,Row_Number 需要排序,但如果您传递文字值,则结果将按解析后的顺序排列。不保证将来的 SQL Server 版本会出现这种情况,因为根据 String_Split 文档,没有官方订购。我怀疑微软会打破这一点,至少在引入一个返回命令的函数版本之前,但与此同时,在编写决定是否发射导弹的代码时,最好不要依赖这个命令。

回报:

Major Minor Revision
----- ----- --------
1     2     3
于 2019-07-29T00:46:30.330 回答