Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

comment diviser et insérer des données CSV dans une nouvelle table en une seule instruction ?

Vous avez besoin d'un moyen de diviser et de traiter la chaîne dans TSQL, il existe de nombreuses façons de le faire. Cet article couvre les avantages et les inconvénients de presque toutes les méthodes :

Tableaux et listes dans SQL Server 2005 et au-delà

Vous devez créer une fonction de fractionnement. Voici comment une fonction de fractionnement peut être utilisée :

SELECT
    *
    FROM YourTable                               y
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value

Je préfère l'approche de la table numérique pour diviser une chaîne dans TSQL - Utilisation d'un Tableau des nombres mais il existe de nombreuses façons de diviser des chaînes dans SQL Server, voir le lien précédent, qui explique les avantages et les inconvénients de chacun.

Pour que la méthode de la table des nombres fonctionne, vous devez effectuer cette configuration de table de temps unique, ce qui créera une table Numbers qui contient des lignes de 1 à 10 000 :

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

Une fois la table Numbers configurée, créez cette fonction de fractionnement :

CREATE FUNCTION inline_split_me (@SplitOn char(1),@param varchar(7998)) RETURNS TABLE AS
   RETURN(SELECT substring(@SplitOn + @param + ',', Number + 1,
                    charindex(@SplitOn, @SplitOn + @param + @SplitOn, Number + 1) - Number - 1)
                 AS Value
          FROM   Numbers
          WHERE  Number <= len(@SplitOn + @param + @SplitOn) - 1
            AND  substring(@SplitOn + @param + @SplitOn, Number, 1) = @SplitOn)

GO 

Vous pouvez maintenant facilement diviser une chaîne CSV en une table et la joindre :

select * from dbo.inline_split_me(';','1;22;333;4444;;') where LEN(Value)>0

SORTIE :

Value
----------------------
1
22
333
4444

(4 row(s) affected)

pour créer une nouvelle table, utilisez ceci :

--set up tables:
DECLARE @Documents table (DocumentID varchar(500), SomeValue varchar(5))
INSERT @Documents VALUES ('1,2,3,4','AAA')
INSERT @Documents VALUES ('5,6'    ,'BBBB')

DECLARE @NewDocuments table (DocumentID int, SomeValue varchar(5))

--populate NewDocuments
INSERT @NewDocuments
    (DocumentID, SomeValue)
SELECT
    c.value,a.SomeValue
    FROM @Documents    a
        CROSS APPLY dbo.inline_split_me(',',a.DocumentID) c

 --show NewDocuments contents:
select * from @NewDocuments

SORTIE :

DocumentID  SomeValue
----------- ---------
1           AAA
2           AAA
3           AAA
4           AAA
5           BBBB
6           BBBB

(6 row(s) affected)

si vous ne souhaitez pas créer de table Numbers et que vous exécutez SQL Server 2005 et versions ultérieures, vous pouvez simplement utiliser cette fonction de fractionnement (aucune table Numbers requise) :

CREATE FUNCTION inline_split_me (@SplitOn char(1),@String varchar(7998))
RETURNS TABLE AS
RETURN (WITH SplitSting AS
           (SELECT
                LEFT(@String,CHARINDEX(@SplitOn,@String)-1) AS Part
                    ,RIGHT(@String,LEN(@String)-CHARINDEX(@SplitOn,@String)) AS Remainder
                WHERE @String IS NOT NULL AND CHARINDEX(@SplitOn,@String)>0
            UNION ALL
            SELECT
                LEFT(Remainder,CHARINDEX(@SplitOn,Remainder)-1)
                    ,RIGHT(Remainder,LEN(Remainder)-CHARINDEX(@SplitOn,Remainder))
                FROM SplitSting
                WHERE Remainder IS NOT NULL AND CHARINDEX(@SplitOn,Remainder)>0
            UNION ALL
            SELECT
                Remainder,null
                FROM SplitSting
                WHERE Remainder IS NOT NULL AND CHARINDEX(@SplitOn,Remainder)=0
           )
           SELECT Part FROM SplitSting
       )
GO