sql >> Base de Datos >  >> RDS >> Sqlserver

¿Cómo dividir e insertar datos CSV en una nueva tabla en una sola declaración?

Necesita una forma de dividir y procesar la cadena en TSQL, hay muchas formas de hacerlo. Este artículo cubre los PRO y los CONTRA de casi todos los métodos:

Arreglos y listas en SQL Server 2005 y posteriores

Necesitas crear una función dividida. Así es como se puede usar una función de división:

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

Prefiero el enfoque de la tabla numérica para dividir una cadena en TSQL:usar un Tabla de números pero hay numerosas formas de dividir cadenas en SQL Server, vea el enlace anterior, que explica los PRO y los CONTRA de cada uno.

Para que funcione el método de tabla de números, debe realizar esta configuración de tabla de tiempo único, que creará una tabla Numbers que contiene filas del 1 al 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 vez que la tabla de Números esté configurada, cree esta función dividida:

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 

Ahora puede dividir fácilmente una cadena CSV en una tabla y unirse a ella:

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

SALIDA:

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

(4 row(s) affected)

para hacer tu nueva mesa usa esto:

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

SALIDA:

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

(6 row(s) affected)

si no desea crear una tabla de números y está ejecutando SQL Server 2005 y versiones posteriores, puede usar esta función de división (no se requiere una tabla de números):

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