Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Split Function and Ordering Issue?

I have the following Split function,

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

When I write,

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

This will give me,

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

I need to maintain the order.

like image 239
Imran Qadir Baksh - Baloch Avatar asked Oct 06 '13 14:10

Imran Qadir Baksh - Baloch


People also ask

Why does order by not work SQL?

This is not a bug. A "table" (and subquery in the FROM clause too) is - according to the SQL standard - an unordered set of rows. Rows in a table (or in a subquery in the FROM clause) do not come in any specific order. That's why the optimizer can ignore the ORDER BY clause that you have specified.

Does SQL automatically order?

We learned that SQL Server doesn't guarantee any order of the results stored in the table, nor in the results set returned from your queries, but we can sort the output by using the order by clause.

How do I split a function in SQL?

The STRING_SPLIT(string, separator) function in SQL Server splits the string in the first argument by the separator in the second argument. To split a sentence into words, specify the sentence as the first argument of the STRING_SPLIT() function and ' ' as the second argument.

How do I split a string with spaces in SQL Server 2012?

You can split the string using XML . You first need to convert the string to XML and replace the space with start and end XML tags . Once the string is converted into XML , you can use XQuery to get the result in proper format.


2 Answers

A simpler function:

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

Sample usage:

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];

Or to return orders from a table ordered by input:

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];
like image 108
Aaron Bertrand Avatar answered Sep 29 '22 20:09

Aaron Bertrand


Your function will need to set an order column (seq in this sample):

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 
like image 35
Mark PM Avatar answered Sep 29 '22 18:09

Mark PM