518 votes

Comment puis-je diviser une chaîne afin que je puisse accéder à l'élément x

À l'aide de SQL Server 2005, comment diviser une chaîne afin que je puisse accéder à l'élément de x?

Prenez, par exemple, la chaîne "Bonjour John Smith". Comment puis-je diviser la chaîne d'un espace et d'accéder à l'élément à l'indice 1 qui devrait revenir "Jean"?

365voto

Nathan Bedford Points 3157

Je ne crois pas que SQL Server a une fonction de répartition, alors que d'autres UDF, la seule autre réponse, je sais, c'est pour détourner l'PARSENAME fonction:

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

PARSENAME prend une chaîne et se divise sur la période de caractère. Il faut un certain nombre comme deuxième argument, et que nombre indique le segment de la chaîne de retour (de l'arrière vers l'avant).

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

Problème évident est que lorsque la chaîne contient déjà une période. Je pense toujours à l'aide d'un fichier UDF est le meilleur moyen...d'autres suggestions?

193voto

Jonesinator Points 1793

Vous pouvez trouver la solution dans SQL Fonction Définie par l'Utilisateur pour Analyser une Chaîne Délimitée utile (à partir Du Projet de Code).

U peut utiliser cette logique simple -

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

110voto

vzczc Points 4923

Tout d'abord, créez une fonction (à l'aide de la CTE, expression de table commune élimine le besoin pour une table temp)

 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 b-a ELSE 4000 end) 
            AS s
        from tokens
      )
    GO

Puis, l'utiliser comme une table (ou de le modifier pour l'adapter à l'intérieur de votre procédure stockée).

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

Mise à jour

Version précédente serait un échec pour la chaîne d'entrée de plus de 4000 caractères. Cette version prend soin de la limitation:

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 b-a ELSE LEN(@str) end) 
    AS Item
from tokens
);

GO

L'utilisation reste la même.

71voto

Aaron Bertrand Points 116343

La plupart des solutions ici, l'utilisation des boucles while ou les expressions cte. Une approche fondée sur le supérieur, je vous promets:

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

Plus sur split fonctions, pourquoi (et la preuve) tandis que les boucles et les expressions cte n'est pas à l'échelle, et de meilleures alternatives, si le fractionnement des chaînes provenant de la couche application:

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

38voto

Nathan Skerl Points 4441

Vous pouvez tirer parti d'un certain Nombre de table pour faire le traitement de chaîne rapide comme l'éclair:

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

Utilisation:

declare @Array varchar(500)
set @Array = 'Hello John smith'

select  s 
from    dbo.ufn_ParseArray(@Array, ' ', 0)
where   i = 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X