Чтение значений, разделенных запятыми, и вставка в таблицу SQL пакетами

У меня есть 4 столбца в таблице sql Offer.

id (PK auto increment), name , org , TourCode Varchar(MAX)

TourCode содержит коды, разделенные запятыми, например (AVG123, JGH12 и т. д.).

У меня есть 40000 TourCode в виде значений, разделенных запятыми.

Мне нужно написать запрос для вставки 4000 строк в таблицу предложений, каждая из которых содержит 10 кодов тура, разделенных запятой. Для всех 4000 строк значение имени и организации остается неизменным, например. «Азбука», «Амазонка»

e.g.

DECLARE @TourCodes VARCHAR(4000);
SET @TourCodes =  'AVG123,JGH12,AVasfG123,JGsdfH12,AVsdgG123,JsdgGH12 , A34G123,J56gGH12, A34G1df23,JgfGH12 ,......'

Output:
╦══════════╦════════════╦═══════════════════╗
║ name     ║ org        ║TourCode           ║
╠══════════╬═══════════ ╬═══════════════════╣
║      ABC ║     Amazon ║AVG123,JGH12       ║
║      ABC ║     Amazon ║AVasfG123,JGsdfH12 ║
║      ABC ║     Amazon ║AVsdgG123,JsdgGH12 ║
║      ABC ║     Amazon ║A34G123,J56gGH12   ║
║      ABC ║     Amazon ║A34G1df23,JgfGH12  ║

Каким должен быть мой лучший подход.

Я использую SQL Server. Заранее спасибо.


person Ravish Kumar    schedule 20.06.2017    source источник
comment
Начиная с SQL-SERVER 2016, здесь может быть полезна табличная функция string_split().   -  person Carsten Massmann    schedule 20.06.2017
comment
@cars10 string_split() разделит значения на основе запятой, и каждая строка будет иметь 1 код тура, а общее количество записей будет 400. Мое требование: я хочу 2 (пример примера) кода тура в строке, а общая строка будет 200.   -  person Ravish Kumar    schedule 20.06.2017


Ответы (3)


Вот как разделить значения, разделенные запятыми, в таблицу (взято из Как разделить значение, разделенное запятыми, на столбцы)

CREATE FUNCTION Split (
      @InputString                  VARCHAR(8000),
      @Delimiter                    VARCHAR(50)
)

RETURNS @Items TABLE (
      Item                          VARCHAR(8000)
)

AS
BEGIN
      IF @Delimiter = ' '
      BEGIN
            SET @Delimiter = ','
            SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
      END

      IF (@Delimiter IS NULL OR @Delimiter = '')
            SET @Delimiter = ','

--INSERT INTO @Items VALUES (@Delimiter) -- Diagnostic
--INSERT INTO @Items VALUES (@InputString) -- Diagnostic

      DECLARE @Item           VARCHAR(8000)
      DECLARE @ItemList       VARCHAR(8000)
      DECLARE @DelimIndex     INT

      SET @ItemList = @InputString
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      WHILE (@DelimIndex != 0)
      BEGIN
            SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
            INSERT INTO @Items VALUES (@Item)

            -- Set @ItemList = @ItemList minus one less item
            SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
            SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      END -- End WHILE

      IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
      BEGIN
            SET @Item = @ItemList
            INSERT INTO @Items VALUES (@Item)
      END

      -- No delimiters were encountered in @InputString, so just return @InputString
      ELSE INSERT INTO @Items VALUES (@InputString)

      RETURN

END -- End Function
GO

после этого

используйте этот код

DECLARE @TourCodes  varchar(4000)
SET @TourCodes  = 'AAAAA,BBBBB,CCCCC,DDDD,EEEE,FFFF , GGG,HHHHH, IIIII,JJJJJ'

DECLARE @T as table (ID int identity, Name varchar(255), Org varchar(255), TourCode varchar(255))

INSERT @T (Name, Org, TourCode)
select 'ABC', 'AMAZON', Item from dbo.split(@TourCodes,',')


Select A.Name, A.Org, ISNULL(A.TourCode, '') + ',' + ISNULL(B.TourCode, '')
from @T A INNER JOIN @T B
ON A.ID = B.ID-1
AND A.ID%2 = 0
person asmgx    schedule 20.06.2017
comment
Это дает неверный результат. Я хочу 2 туркода на значение, и это дает случайный результат - person Ravish Kumar; 20.06.2017
comment
я изменил запрос, попробуйте сейчас - person asmgx; 20.06.2017
comment
Привет @asmgx ..Спасибо за ваш ответ. Но у этого запроса есть проблема. Что, если я хочу 10 Tourcode на строку. Мне нужно изменить весь запрос. - person Ravish Kumar; 20.06.2017
comment
в этом случае вам лучше зациклить значения, разделенные запятыми, и после 10 запятых изменить запятую на точку с запятой, а затем разделить на точку с запятой - person asmgx; 20.06.2017

Тогда попробуйте сначала это, а затем попробуйте разделить SP с точкой с запятой

эта функция будет отделять каждое N количество туров точкой с запятой

create FUNCTION GroupBySemicolon (
      @TourCodes                  VARCHAR(8000),
      @HowManyTours               int
)

RETURNS varchar(8000)
AS
BEGIN


DECLARE @i int
DECLARE @Pos int

SET @i = 0
SET @Pos = 1
WHILE @Pos <> 0
BEGIN
    SET @i= @i+1
    SET @Pos = CHARINDEX( ',', @TourCodes,@Pos + 1)
    --SELECT @Pos
    IF @i = @HowManyTours and @Pos > 0
    BEGIN
        SET @i = 0

        SET @TourCodes = LEFT(@TourCodes,@Pos-1) + ';' + RIGHT(@TourCodes, LEN(@TourCodes) - @Pos)
    END

END




RETURN @TourCodes

END

select dbo.GroupBySemicolon( '111,222222,333,44,555555,66 ,7777,8888, 99999,000000', 4)
person asmgx    schedule 20.06.2017
comment
Вместо точки с запятой следующий набор из 4 должен находиться в следующей строке. Если имеется 12 кодов туров, а значение HowManyTours равно 4, то у нас должно быть 3 строки по 4 кода туров в каждой!! - person Ravish Kumar; 20.06.2017
comment
ВЫБЕРИТЕ 'ABC', 'Amazon', dbo.Split(dbo.GroupBySemicolon('111,222222,333,44,555555,66,7777,8888, 99999,000000', 4), ';') - person asmgx; 20.06.2017
comment
если это ответ на ваш вопрос, то отметьте его как ОТВЕТ - person asmgx; 20.06.2017

А как насчет этого решения?

DECLARE @TourCodes VARCHAR(4000);
SET @TourCodes =  ' AVG123   , JGH12,AVasfG123,JGsdfH12,AVsdgG123,JsdgGH12 , A34G123,J56gGH12, A34G1df23,JgfGH12';

with rcrs AS (
select rtrim(ltrim(LEFT(@TourCodes,charindex(',',@TourCodes)-1))) first,     
       SUBSTRING(@TourCodes+',',charindex(',',@TourCodes)+1,4000) other,
       0 flg
union all
select rtrim(ltrim(LEFT(other,charindex(',',other)-1))) first,
       SUBSTRING(other,charindex(',',other)+1,4000) other ,
       flg+1 flg FROM rcrs WHERE charindex(',',other)>0

) 
SELECT a.first one,b.first two from rcrs a 
INNER JOIN rcrs b ON b.flg=a.flg+1 WHERE a.flg%2=0

В рекурсивном CTE строка разбивается с самого начала.

Следует отметить, что я добавил к исходной строке в первой части рекурсивного CTE дополнительный ','. Это гарантирует, что все слова будут «съедены» CTE и затем могут быть обработаны основным выбором с использованием трюка по модулю (%) для определения того, какая часть входит в столбец one или two.

Результат для этого примера:

one       two

AVG123    JGH12
AVasfG123 JGsdfH12
AVsdgG123 JsdgGH12
A34G123   J56gGH12
A34G1df23 JgfGH12

См. демонстрацию здесь: http://rextester.com/WAA6224

Изменить

Очевидно, у меня было слишком много свободного времени ;-) ...
и поэтому я решил попробовать, смогу ли я на самом деле собрать весь материал в коллекцию из десяти столбцов, как того хочет ОП. . Я до сих пор не совсем понимаю, как должен был выглядеть результат, но вот еще один снимок:

DECLARE @TourCodes VARCHAR(4000);
SET @TourCodes =  REPLACE(REPLACE(
                  ' AVG123   , JGH12,AVasfG123,JGsdfH12,AVsdgG123,JsdgGH12 , A34G123,J56gGH12, A34G1df23,JgfGH12,
                    AVG1234   , JGH126,AVasfG1238,JGsdfH122,AVsdgG1235,JsdgGH127 , A34G1239,J56gGH12a, A34G1df23c,JgfGH12e,
                    AVG1235   , JGH127,AVasfG1239,JGsdfH123,AVsdgG1236,JsdgGH128 , A34G1230,J56gGH12b, A34G1df23d,JgfGH12f',
                   char(10),''),char(13),''); -- this is just a slightly extended sample input string

with rcrs AS (
select rtrim(ltrim(LEFT(@TourCodes,charindex(',',@TourCodes)-1))) first,

       SUBSTRING(@TourCodes+',',charindex(',',@TourCodes)+1,4000) other, 0 flg
union all
select rtrim(ltrim(LEFT(other,charindex(',',other)-1))) first,
       SUBSTRING(other,charindex(',',other)+1,4000) other , flg+1 flg FROM rcrs WHERE charindex(',',other)>0 and flg<30

), cmbn AS (
  SELECT a.flg/20 ii,(a.flg/2)%10 ij ,a.first+','+b.first tc FROM rcrs a
  LEFT JOIN rcrs b ON b.flg=a.flg+1
  WHERE a.flg%2=0
)
SELECT ii,'ABC' name,'Amazon' org, MAX(CASE ij WHEN 0 THEN tc END) tc1,
  MAX(CASE ij WHEN 1 THEN tc END) tc2,
  MAX(CASE ij WHEN 2 THEN tc END) tc3,
  MAX(CASE ij WHEN 3 THEN tc END) tc4,
  MAX(CASE ij WHEN 4 THEN tc END) tc5,
  MAX(CASE ij WHEN 5 THEN tc END) tc6,
  MAX(CASE ij WHEN 6 THEN tc END) tc7,
  MAX(CASE ij WHEN 7 THEN tc END) tc8,
  MAX(CASE ij WHEN 8 THEN tc END) tc9,
  MAX(CASE ij WHEN 9 THEN tc END) tc10
FROM cmbn GROUP BY ii

Результат выглядит следующим образом:

ii name org    tc1            tc2                  tc3                  tc4                tc5                 tc6            tc7                  tc8                  tc9                tc10
0  ABC  Amazon AVG123,JGH12   AVasfG123,JGsdfH12   AVsdgG123,JsdgGH12   A34G123,J56gGH12   A34G1df23,JgfGH12   AVG1234,JGH126 AVasfG1238,JGsdfH122 AVsdgG1235,JsdgGH127 A34G1239,J56gGH12a A34G1df23c,JgfGH12e
1  ABC  Amazon AVG1235,JGH127 AVasfG1239,JGsdfH123 AVsdgG1236,JsdgGH128 A34G1230,J56gGH12b A34G1df23d,JgfGH12f     

см. здесь: http://rextester.com/ZJNV34690

Или, если вы хотите, чтобы все десять Tourcodes были в одном столбце, вы можете сделать

SELECT ii,'ABC' name,'Amazon' org, 
           MAX(CASE ij WHEN 0 THEN tc END)+' '+
  COALESCE(MAX(CASE ij WHEN 1 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 2 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 3 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 4 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 5 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 6 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 7 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 8 THEN tc END)+' ','')+
  COALESCE(MAX(CASE ij WHEN 9 THEN tc END)+' ','') tourCodes
FROM cmbn GROUP BY ii

в основном выберите. См. здесь http://rextester.com/AQCG28977

результат:

ii name org     tourCodes
0  ABC  Amazon  AVG123,JGH12 AVasfG123,JGsdfH12 AVsdgG123,JsdgGH12 A34G123,J56gGH12 A34G1df23,JgfGH12 AVG1234,JGH126 AVasfG1238,JGsdfH122 AVsdgG1235,JsdgGH127 A34G1239,J56gGH12a A34G1df23c,JgfGH12e 
1  ABC  Amazon  AVG1235,JGH127 AVasfG1239,JGsdfH123 AVsdgG1236,JsdgGH128 A34G1230,J56gGH12b A34G1df23d,JgfGH12f 
person Carsten Massmann    schedule 20.06.2017
comment
Требование немного другое. У меня есть 40000 TourCode, доступных в виде значений, разделенных запятыми. Мне нужно написать запрос, чтобы вставить 4000 строк в таблицу предложений, причем каждая строка содержит 10 кодов тура. 10 кодов тура в каждой строке должны быть разделены запятой. - person Ravish Kumar; 20.06.2017
comment
Ну, это не бесплатная служба кодирования. Если вы можете использовать мой фрагмент, чтобы найти собственное решение, то это будет в лучшем духе stackoverflow. В противном случае: продолжайте искать / пробовать. Удачи! ;-) - person Carsten Massmann; 20.06.2017