Сохранить несколько разделенных запятыми строк во временной таблице - PullRequest
0 голосов
/ 25 ноября 2018

Заданные строки:

string 1: 'A,B,C,D,E'
string 2: 'X091,X089,X051,X043,X023'

Хотите сохранить во временной таблице как:

String1     String2
---------------------
A           X091
B           X089
C           X051
D           X043
E           X023

Tried : Создана пользовательская функция с именем udf_split ивставить в таблицу для каждого столбца.

DECLARE @Str1 VARCHAR(MAX) = 'A,B,C,D,E'
DECLARE @Str2 VARCHAR(MAX) = 'X091,X089,X051,X043,X023'

IF OBJECT_ID('tempdb..#TestString') IS NOT NULL DROP TABLE #TestString;

CREATE TABLE #TestString (string1 varchar(100),string2 varchar(100));

INSERT INTO #TestString(string1) SELECT Item FROM udf_split(@Str1,',');
INSERT INTO #TestString(string2) SELECT Item FROM udf_split(@Str2,',');

Но получить следующий результат:

SELECT * FROM #TestString

string1 string2
-----------------
A       NULL
B       NULL
C       NULL
D       NULL
E       NULL
NULL    X091
NULL    X089
NULL    X051
NULL    X043
NULL    X023    

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Вам необходимо вставить обе части каждой строки вместе.В противном случае вы получите в каждой строке один столбец, содержащий null - именно это и произошло в вашей попытке.

Во-первых, я бы порекомендовал вообще не возиться со строками, разделенными запятыми, в базе данных, если это так.возможно.
Если у вас есть контроль над вводом, лучше использовать табличные переменные или xml.Если вы этого не сделаете, чтобы разбить строки в любой версии до 2016 года, я бы порекомендовал сначала прочитать Аарона Бертранда «Разделить строки» правильным способом - или следующим лучшим способом .В 2016 году вы должны использовать встроенную функцию string_split.

Для такого рода вещей вы хотите использовать функцию разделения, которая возвращает как элемент, так и его местоположение в исходной строке.К счастью для вас, Джефф Моден уже написал такую ​​функцию разделения, и это очень популярная, высокопроизводительная функция.
Вы можете прочитать все об этом на Tally OH!Улучшенная функция CSV Splitter для SQL 8K .

Итак, вот функция Джеффа:

CREATE FUNCTION [dbo].[DelimitedSplit8K]
--===== Define I/O parameters
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE!  IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
     -- enough to cover VARCHAR(8000)
  WITH E1(N) AS (
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                ),                          --10E+1 or 10 rows
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
                     -- for both a performance gain and prevention of accidental "overruns"
                 SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT 1 UNION ALL
                 SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
                ),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
                 SELECT s.N1,
                        ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
                   FROM cteStart s
                )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
        Item       = SUBSTRING(@pString, l.N1, l.L1)
   FROM cteLen l
;

и вот как вы ее используете:

DECLARE @Str1 VARCHAR(MAX) = 'A,B,C,D,E'
DECLARE @Str2 VARCHAR(MAX) = 'X091,X089,X051,X043,X023'

IF OBJECT_ID('tempdb..#TestString') IS NOT NULL DROP TABLE #TestString;

CREATE TABLE #TestString (string1 varchar(100),string2 varchar(100));

INSERT INTO #TestString(string1, string2) 
SELECT A.Item, B.Item
FROM DelimitedSplit8K(@Str1,',') A
JOIN DelimitedSplit8K(@Str2,',') B
ON A.ItemNumber = B.ItemNumber;
0 голосов
/ 25 ноября 2018

Мое предложение использует два независимых рекурсивных разбиения.Это позволяет нам преобразовать две строки в два набора с индексом позиции.Финальные SELECT объединят два набора по их индексу позиции и вернут отсортированный список:

DECLARE @str1 VARCHAR(1000)= 'A,B,C,D,E';
DECLARE @str2 VARCHAR(1000)= 'X091,X089,X051,X043,X023';

;WITH
 --split the first string
 a1 AS (SELECT n=0, i=-1, j=0 UNION ALL SELECT n+1, j, CHARINDEX(',', @str1, j+1) FROM a1 WHERE j > i)
,b1 AS (SELECT n, SUBSTRING(@str1, i+1, IIF(j>0, j, LEN(@str1)+1)-i-1) s FROM a1 WHERE i >= 0)
 --split the second string
,a2 AS (SELECT n=0, i=-1, j=0 UNION ALL SELECT n+1, j, CHARINDEX(',', @str2, j+1) FROM a2 WHERE j > i)
,b2 AS (SELECT n, SUBSTRING(@str2, i+1, IIF(j>0, j, LEN(@str2)+1)-i-1) s FROM a2 WHERE i >= 0)
--join them by the index
SELECT b1.n
      ,b1.s AS s1
      ,b2.s AS s2
FROM b1
INNER JOIN b2 ON b1.n=b2.n
ORDER BY b1.n;

Результат

n   s1  s2
1   A   X091
2   B   X089
3   C   X051
4   D   X043
5   E   X023

ОБНОВЛЕНИЕ: Если у вас v2016 + ...

С SQL-Server 2016+ вы можете использовать OPENJSON с небольшой заменой строк для преобразования строк CSV в массив JSON:

SELECT a.[key]
      ,a.value AS s1
      ,b.value AS s2
FROM OPENJSON('["' + REPLACE(@str1,',','","') + '"]') a
INNER JOIN(SELECT * FROM OPENJSON('["' + REPLACE(@str2,',','","') + '"]')) b ON a.[key]=b.[key]
ORDER BY a.[key];

КромеSTRING_SPLIT() этот подход возвращает key как индекс, начинающийся с нуля, элемента в массиве .Результат тот же ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...