Разбейте строку '1/10/2/20/3/30/4/40' на две колонки, чтобы проверить подробности - PullRequest
0 голосов
/ 17 февраля 2020
string = '1/10/2/20/3/30/4/40'
output = col1  |   col2
           1   |    10
           2   |    20
           3   |    30
           4   |    40

Я пробовал ниже код:

DECLARE @TEXT VARCHAR(60) = '1/10/2/20/3/30/4/40', @POSITION INT=1
CREATE TABLE #TEMP(VAL1 INT,VAL2 INT)
WHILE (LEN(@TEXT) >= @POSITION)
BEGIN
  INSERT INTO #TEMP VALUES(SUBSTRING(@TEXT,@POSITION,1),SUBSTRING(@TEXT,@POSITION+2,2))
  SET @POSITION = @POSITION+5
END

SELECT * FROM #TEMP

это дает вывод, но это больше похоже на жестко закодированный.

Ответы [ 2 ]

1 голос
/ 17 февраля 2020

В следующий раз, пожалуйста, укажите версию SQL -Server ...

Следующее решение работает практически с любой версией, если у вас версия v2016 +, возможно, есть более подходящие подходы. Попробуйте это:

DECLARE @TEXT VARCHAR(60) = '1/10/2/20/3/30/4/40';

WITH Casted(ToXml) AS
(
    SELECT CAST('<x>' + REPLACE(@TEXT,'/','</x><x>') + '</x>' AS XML)
)
,TallyOddNumbers(OddNumber) AS
(   
    SELECT TOP((SELECT ToXml.value('count(/x)','int')/2 FROM Casted)) (ROW_NUMBER() OVER(ORDER BY (SELECT NULL)))*2-1 FROM master..spt_values
)
SELECT ToXml.value('/x[sql:column("OddNumber")][1]','int') AS Col1
      ,ToXml.value('/x[sql:column("OddNumber")+1][1]','int') AS Col1
FROM Casted
CROSS JOIN TallyOddNumbers;

Идея вкратце:

  • Первый cte "Casted" создаст XML из вашей строки.
  • The второй cte "TallyOddNumbers" будет использовать ROW_NUMBER() против master..spt_values (здесь можно использовать любой больший набор) для создания набора работающих нечетных чисел
  • В вычисленном предложении TOP будет использоваться XML.value() с count(), чтобы найти необходимое количество пар элементов.
  • В последнем запросе будет использоваться подсчет для получения значений по их позициям.

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

ОБНОВЛЕНИЕ для версии 2016 +

В своем собственном ответе вы используете string_split() (что не очень хорошая идея из-за негарантированного порядка сортировки). Но это указывает на версию v2016 +.

Вы можете попробовать этот альтернативный подход

DECLARE @TEXT VARCHAR(60) = '1/10/2/20/3/30/4/40';


WITH ToJson(j) AS(SELECT CONCAT('[',REPLACE(@TEXT,'/',','),']'))
SELECT p.Col1
      ,p.Col2
FROM
(
    SELECT A.[key] /2 AS GroupIndex
          ,CONCAT('Col',A.[key]%2 +1) AS ColumnName
          ,A.[value] AS TheValue 
    FROM ToJson
    CROSS APPLY OPENJSON(j) A
) t
PIVOT
(
    MAX(TheValue) FOR ColumnName IN(Col1,Col2)
) p;

Идея вкратце:

  • Cte преобразует ваш CSV -лист к массиву JSON
  • Мы используем OPENJSON для чтения этого массива
  • key - позиция элементов. Вместе с %2 (оператором по модулю) мы получаем вычисляемое переменное имя столбца
  • Наконец, мы можем использовать PIVOT для разбивки ваших значений на Col1 и Col2.
  • . A.[key] /2 будет использовать трюк с целочисленными делениями для создания одного числа на группу (в противном случае вы увидите только последний ряд).
0 голосов
/ 17 февраля 2020

Я пытался создать временные таблицы. И добавление одного di git в одну временную таблицу и не одного di git в другую временную таблицу. И помещая значения обеих таблиц в другую временную таблицу.

Код:
Примечание: @series - строка, которую я передал.

select value into #value from string_split(@series,'/')

create table #position(var int identity(1,1),var1 int)

insert into #position(var1)    
select value from #value    where value like '_'

create table #position2(var int,var2 int)

insert into #position2(var2)   
select value from #value where value not like '_'

create table #final(var1 int,var2 int)

insert into #final(var1,var2)    
select p1.var1,p2.var2 from #position p1                
      join #position2 p2 on p1.var=p2.var

select * from #final
...