Как разделить и вставить данные CSV в новую таблицу в одном выражении? - PullRequest
1 голос
/ 16 июля 2010

У меня есть таблица с именем «Документы», содержащая следующий столбец:

DocumentID

У меня есть данные в формате - @DocID = 1,2,3,4

Как мне вставить эти documentID в отдельные строки, используя один запрос?

Ответы [ 2 ]

6 голосов
/ 16 июля 2010

Вам нужен способ разбить и обработать строку в TSQL, есть много способов сделать это.В этой статье рассматриваются преимущества и недостатки практически каждого метода:

Массивы и списки в SQL Server 2005 и более поздних версиях

Вам необходимо создать функцию разделения.Вот как можно использовать функцию разделения:

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

Я предпочитаю подход таблицы чисел для разделения строки в TSQL - Использование таблицы чисел , но существует множество способов разделенияСтроки в SQL Server, см. предыдущую ссылку, в которой объясняются плюсы и минусы каждого из них.

Чтобы метод таблицы чисел работал, вам необходимо выполнить эту настройку единой таблицы, которая создаст таблицу Numbers содержит строки от 1 до 10000:

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)

После настройки таблицы чисел создайте эту функцию разделения:

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 

Теперь можно легко разбить строку CSV настол и присоединитесь к нему:

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

ВЫХОД:

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

(4 row(s) affected)

, чтобы создать новую таблицу, используйте это:

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

ВЫХОД:

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

(6 row(s) affected)

Если вы не хотите создавать таблицу Numbers и используете SQL Server 2005 и более поздние версии, вы можете просто использовать эту функцию разделения (таблица 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
3 голосов
/ 16 июля 2010

+ 1 для подробного объяснения К.М.Это выполнит работу быстро, но, возможно, не обязательно наиболее эффективно (см. Ответ KM для всех вариантов)

Мой быстрый ответ:

Установка SQL # (этобесплатно и очень полезно)

Тогда

INSERT INTO Documents (documentId)
SELECT SplitVal FROM SQL#.String_Split(@DocId, ',', 1) 
...