Разбить строку на два столбца с разделителем -> - PullRequest
0 голосов
/ 06 марта 2020

У меня есть следующая строка для разделения на два столбца с заданным форматом From и To.

Данная строка:

DECLARE @String VARCHAR(MAX) = 'A->B->C->D'

Ожидаемый результат :

From    To
-----------
A       B
B       C
C       D

Пробовал:

DECLARE @String VARCHAR(MAX) = 'A->B->C->D' 
SELECT CASE WHEN item LIKE '%-' THEN REPLACE(item,'-','') END AS [From],
       CASE WHEN item NOT LIKE '%-' THEN item END AS [To]   
FROM dbo.f_Split(@String,'>')

Ответы [ 3 ]

2 голосов
/ 06 марта 2020

Попробуйте:

DECLARE @String VARCHAR(MAX) = 'A->B->C->D';


DECLARE @StringXML XML = CAST('<a>' + REPLACE(@String, '->', '</a><a>') + '</a>' AS XML);


WITH DataSource ([RowID], [RowValue]) AS
(
    SELECT  ROW_NUMBER() OVER (ORDER BY T.c ASC)
           ,T.c.value('.', 'CHAR(1)')
    FROM @StringXML.nodes('a') T(c)
)
SELECT DS1.[RowValue] AS [From]
      ,DS2.[RowValue] AS [TO]
FROM DataSource DS1
INNER JOIN DataSource DS2
    ON DS1.[RowID] + 1 = DS2.[RowID];

Идея состоит в том, чтобы разделить значения и упорядочить их. Затем просто выполните присоединение к последней строке, установленной для себя.

1 голос
/ 06 марта 2020

Еще одно решение с использованием позиции и +1:

DECLARE @String VARCHAR(MAX) = 'A->B->C->D->E';

DECLARE @YourStringAsXml XML=CAST('<x>' + REPLACE(@String, '->', '</x><x>') + '</x>' AS XML);

- запрос

WITH tally(nr) AS 
(
    SELECT TOP (@YourStringAsXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
    FROM master..spt_values
)
SELECT @YourStringAsXml.value('/x[sql:column("nr")][1]','varchar(10)') AS FromNode
      ,@YourStringAsXml.value('/x[sql:column("nr")+1][1]','varchar(10)') AS ToNode
FROM tally;

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

  • Мы преобразуем строку в XML
  • Мы используем tally-on-the-fly с вычисленным предложением TOP(), чтобы получить список бегущих чисел (лучше было - и в любом случае очень красивый - таблица числовых чисел).
  • Теперь мы можем выбрать элементы по их положению (sql:column()) и соседу, просто добавив +1 к этой позиции
1 голос
/ 06 марта 2020

Вы можете REPLACE строку перед ее обработкой и напрямую применять соединения, чтобы получить ожидаемый результат. Учитывая, что функция dbo.f_Split возвращает столбец item.

DECLARE @String VARCHAR(MAX) = 'A->B->C->D->E->F->G';

SET @String = REPLACE(@String, '->', '>')

WITH CTE(RowNumber, RowData) AS
(
    SELECT
        ROW_NUMBER() OVER (ORDER BY S1.item) AS RowNumber,
        S1.item AS RowData
    FROM dbo.f_Split(@String,'>') S1
)
SELECT
    C1.RowData AS [From], 
    C2.RowData AS [To]
FROM CTE C1
INNER JOIN CTE C2 ON C1.RowNumber + 1 = C2.RowNumber
...