Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

come dividere e inserire dati CSV in una nuova tabella in un'unica istruzione?

Hai bisogno di un modo per dividere ed elaborare la stringa in TSQL, ci sono molti modi per farlo. Questo articolo copre i PRO ei CONTRO di quasi tutti i metodi:

Array ed elenchi in SQL Server 2005 e versioni successive

Devi creare una funzione di divisione. Ecco come è possibile utilizzare una funzione di divisione:

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

Preferisco l'approccio della tabella dei numeri per dividere una stringa in TSQL - Usando un Tabella dei numeri ma ci sono molti modi per dividere le stringhe in SQL Server, vedi il link precedente, che spiega i PRO ei CONTRO di ciascuno.

Affinché il metodo della tabella dei numeri funzioni, devi eseguire questa configurazione dell'orario una tantum, che creerà una tabella Numbers che contiene righe da 1 a 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)

Una volta impostata la tabella dei numeri, crea questa funzione di divisione:

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 

Ora puoi facilmente dividere una stringa CSV in una tabella e unirti ad essa:

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

USCITA:

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

(4 row(s) affected)

per farti un nuovo tavolo usa questo:

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

USCITA:

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

(6 row(s) affected)

se non vuoi creare una tabella di Numbers e stai utilizzando SQL Server 2005 e versioni successive, puoi semplicemente utilizzare questa funzione di divisione (non è richiesta alcuna tabella di Numbers):

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