Как вставить вывод string_split в таблицу? - PullRequest
1 голос
/ 08 марта 2019

У меня есть строка, которую нужно вставить в таблицу после извлечения из нее значений. Пример строки выглядит так:

111111,1111,11.11,'2019-01-01-11.11.11.111111'#222222,2222,22.22,'2019-02-02-22.22.22.222222'

Используя string_split, я могу разбить значения на разные строки:

declare @s varchar(1000)
set @s = '111111,1111,11.11,''2019-01-01-11.11.11.111111''#222222,2222,22.22,''2019-02-02-22.22.22.222222'''

select value from string_split(@s, '#')

--Output
--111111,1111,11.11,'2019-01-01-11.11.11.111111'
--222222,2222,22.22,'2019-02-02-22.22.22.222222'

Становится интересно.

Вывод необходимо вставить в таблицу. Я думал о динамическом SQL, но не слишком люблю это:

declare @SQLstatment varchar(1000)
set @SQLstatment = 'insert into MyTable (Col1,Col2,Col3,Col4) values (' + OUTPUT_FROM_SPLIT + ')'
exec (@SQLstatment)

Становится интереснее.

Col4 относится к типу данных DB2 timestamp. Мне нужно преобразовать его в тип данных SQL Server 2016 datetime2, используя это заявление, которое я написал:

declare @DB2_timpstamp varchar(30) = '2019-02-25-11.22.33.456789'
select convert(datetime2, stuff(stuff(stuff(@DB2_timpstamp, 17, 1, ':'), 14, 1, ':'), 11, 1, ' '))

Задача

Я не могу заставить все это работать.

Я хочу максимально избегать использования динамического SQL. Скорее всего, я должен использовать петли. Решение будет выглядеть так:

while(SOME_CONDITION)
begin
    insert into MyTable (Col1,Col2,Col3,Col4) values
        (Val1,Val2,Val3,convert(datetime2, stuff(stuff(stuff(Val4, 17, 1, ':'), 14, 1, ':'), 11, 1, ' ')))
    LOOP_VARIABLE_INCREMENT
end

Ответы [ 4 ]

2 голосов
/ 08 марта 2019

Вам нужно разделить дважды:

declare @s varchar(1000)
set @s = '111111,1111,11.11,''2019-01-01-11.11.11.111111''#222222,2222,22.22,''2019-02-02-22.22.22.222222'''

;WITH cte AS (
  select value
  from string_split(@s, '#')
)
SELECT
   MAX(CASE WHEN ord=1 THEN v END) AS col1,
   MAX(CASE WHEN ord=2 THEN v END) AS col2,
   MAX(CASE WHEN ord=3 THEN v END) AS col3,
   MAX(CASE WHEN ord=4 THEN v END) AS col4
FROM cte
CROSS APPLY (SELECT value AS v, ROW_NUMBER() OVER(ORDER BY 1/0) AS ord 
       FROM  STRING_SPLIT([value], ',')) s
GROUP BY value;

db <> Fiddle demo

1 голос
/ 08 марта 2019

ОК, не эксперт по функциям преобразования SQL Server, но это поможет вам в правильном направлении:

with 
r (value) as ( -- raw varchar value
  select value from string_split(@s, '#')
),
x (col1, col2, col3, col4) as ( -- values in separate columns
  select 
    substring(value, 1, 10) as col1, -- fix conversion here
    substring(value, 11, 10) as col2, -- fix conversion here
    substring(value, 21, 10) as col3, -- fix conversion here
    substring(value, 31, 10) as col4, -- fix conversion here
  from r
)
insert into MyTable (Col1,Col2,Col3,Col4) -- insert now
select col1, col2, col3, col4 from x

Как видите, цикл не нужен.Просто нормальный SQL подойдет.Конечно, вам нужно немного адаптировать формулы преобразования, но это довольно близко подойдет вам.

1 голос
/ 08 марта 2019

Используя power из DelimitedSplit8k_Lead, вы можете разделить элементы дважды и узнать их порядковое положение (очень важно для поворота). Дайте вам хорошее простое утверждение:

DECLARE @DataSet varchar(MAX) = '111111,1111,11.11,''2019-01-01-11.11.11.111111''#222222,2222,22.22,''2019-02-02-22.22.22.222222''';
--INSERT INTO MyTable (Col1,Col2,Col3,Col4)
SELECT MAX(CASE WHEN C.ItemNumber = 1 THEN C.item END),
       MAX(CASE WHEN C.ItemNumber = 2 THEN C.item END),
       MAX(CASE WHEN C.ItemNumber = 3 THEN C.item END),
       MAX(CASE WHEN C.ItemNumber = 4 THEN TRY_CONVERT(Datetime2(6),STUFF(STUFF(STUFF(C.item,17,1,':'),14,1,':'),11,1,'T')) END)
FROM dbo.DelimitedSplit8K_lead(@DataSet,'#') R
     CROSS APPLY dbo.DelimitedSplit8K_lead (REPLACE(R.item,'''',''),',') C --Because we don't want those nasty single quotes!
GROUP BY R.item;
0 голосов
/ 08 марта 2019

Вот решение, которое разбивает строку дважды и сохраняет порядок столбцов, даже если они имеют переменную длину. Я использовал этот трюк , чтобы сохранить порядок значений, возвращаемых из STRING_SPLIT. Я не сохранил порядок «строк» ​​в исходной строке, поскольку не имеет значения, в каком порядке они вставлены.

DECLARE @s VARCHAR(1000) = '111111,1111,11.11,''2019-01-01-11.11.11.111111''#222222,2222,22.22,''2019-02-02-22.22.22.222222''';
DECLARE  @c VARCHAR(1) = ','
;WITH CTE AS 
(
    SELECT s.rowNum, t.value, t.columnNum
    FROM 
    (
        SELECT s.value, ROW_NUMBER() OVER(ORDER BY s.value) AS rowNum
        FROM STRING_SPLIT(@s, '#')s
    )s
    OUTER APPLY 
    (
        SELECT T.VALUE, ROW_NUMBER() OVER(ORDER BY CHARINDEX(@C + t.value + @C, @C + s.value + @C))AS columnNum
        FROM STRING_SPLIT(s.value, ',') t
    )t
)
    INSERT INTO myTable (col1, col2, col3, col4)) --do your conversions here
    SELECT MAX(CASE WHEN columnNum = 1 THEN value END), MAX(CASE WHEN columnNum = 2 THEN value END), MAX(CASE WHEN columnNum = 3 THEN value END), MAX(CASE WHEN columnNum = 4 THEN value END)
    FROM cte c
    GROUP BY rownum
...