2015-01-13 2 views
1

Моей цель состоит в том, чтобы преобразовать строку SQLРазделите строку sql на ',' и '|'

'element1|value,element2|value2,element3|value3' 

в

'<element1>value</element1> 
<element2>value2</element1> 
<element3>value3</element1>' 

Мои мысли

declare @test as varchar(max) = 'element1|value1,element2|value2,element3|value3' 

SELECT CHARINDEX(',',@test) 

SELECT SUBSTRING(@test,0,CHARINDEX(',',@test)) 

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

+1

Нужно ли это делать в SQL? SQL не предназначен для разделения строк. Есть ли еще один слой, который мог бы выполнить синтаксический анализ? –

+0

@DStanley Вы не представляете, насколько я желаю, чтобы это было возможно где-то еще. – DidIReallyWriteThat

+0

Является ли ваш желаемый результат несколькими рядами на входную строку, например, ваш образец? –

ответ

3

Вы можете разобрать строки с помощью XML функциональность:

;WITH cte AS (SELECT testString = 'element1|value,element2|value2,element3|value3' 
       UNION SELECT 'test,1,2,3' 
      ) 
    ,SplitString AS (SELECT testString, 
          CONVERT(XML,'<String><Section>'+ REPLACE(REPLACE(testString ,'|',','),',', '</Section><Section>') + '</Section></String>') AS xmlString 
         FROM cte 
        )  
SELECT xmlString.value('/String[1]/Section[1]','varchar(100)') AS Col1 
     ,xmlString.value('/String[1]/Section[2]','varchar(100)') AS Col2 
     ,xmlString.value('/String[1]/Section[3]','varchar(100)') AS Col3 
     ,xmlString.value('/String[1]/Section[4]','varchar(100)') AS Col4 
FROM SplitString 

Здесь я просто изменил ваш | в , и сделать все расщеплению одним махом, но если это не все даже пары вы могли бы это сделать в два этапа, сначала расщепление на |, затем на ,.

Вы также можете посмотреть в PARSENAME(), но он ограничен 4 разделов, или вы можете создать PARSE функцию, как:

/******************************************************************************************** 
     Create Parse Function 
********************************************************************************************/ 
CREATE FUNCTION dbo.FN_PARSE(@chunk VARCHAR(4000), @delimiter CHAR(1), @index INT) 
RETURNS VARCHAR(1000) 
AS 
BEGIN 
    DECLARE 
     @curIndex INT = 0, 
     @pos INT = 1, 
     @prevPos INT = 0, 
     @result VARCHAR(1000) 
    WHILE @pos > 0 
    BEGIN 
     SET @pos = CHARINDEX(@delimiter, @chunk, @prevPos); 
     IF(@pos > 0) 
     BEGIN -- Characters between position and previous position 
      SET @result = SUBSTRING(@chunk, @prevPos, @[email protected]) 
     END 
     ELSE 
     BEGIN -- Last Delim 
      SET @result = SUBSTRING(@chunk, @prevPos, LEN(@chunk)) 
     END 
     IF(@index = @curIndex) 
     BEGIN 
      RETURN @result 
     END 
     SET @prevPos = @pos + 1 
     SET @curIndex = @curIndex + 1; 
    END 
    RETURN '' -- Else Empty 
END 

, который затем называется просто:

;WITH cte AS (SELECT testString = 'element1|value,element2|value2,element3|value3' 
       UNION SELECT 'test,1,2,3' 
      ) 
SELECT dbo.FN_PARSE(testString ,'|', 0) AS Col1 
     ,dbo.FN_PARSE(testString ,'|', 1) AS Col2 
     ... 
FROM cte 

Обратите внимание на индексирование для секции начинается с 0 в вышеуказанной функции.

В настоящее время я заинтересован в версии XML, но не провел много сравнительного тестирования.

+0

Мне это очень нравится. Кроме того, изменение конца SELECT только на SELECT xmlString.query ('/') возвращается как XML-документ, что является удивительным. Im, глядя теперь на объединение, чтобы выглядеть как XML-документ под одним корневым узлом с парными именами/значениями – DidIReallyWriteThat

0

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

DECLARE @Sample NVARCHAR(500), 
     @ElementBasedXML NVARCHAR(500), 
     @AttributeBasedXML NVARCHAR(500); 

SELECT @Sample = N'element1|value,element2|value2,element3|value3', 
     @ElementBasedXML = N'<$2>$3</$2>' + NCHAR(10), 
     @AttributeBasedXML = N'<row $2="$3" />' + NCHAR(10); 

SELECT SQL#.RegEx_Replace4k(@Sample, N'(([^|,]+)\|([^|,]+)),?', @ElementBasedXML, 
          -1, 1, Null) AS [ElementBased], 
     SQL#.RegEx_Replace4k(@Sample, N'(([^|,]+)\|([^|,]+)),?', @AttributeBasedXML, 
          -1, 1, Null) AS [AttributeBased]; 

Возвращает:

ElementBased 
------------ 
<element1>value</element1> 
<element2>value2</element2> 
<element3>value3</element3> 

AttributeBased 
-------------- 
<row element1="value" /> 
<row element2="value2" /> 
<row element3="value3" /> 

Или, вы можете разделить строку на запятые внутри КТР (дает неограниченное количество пар ключ-значение, разделенных символами трубы), а затем разделив эти пары на их сингл разделитель:

DECLARE @Sample2 NVARCHAR(500); 

SELECT @Sample = N'element1|value,element2|value2,element3|value3'; 

;WITH kvpairs AS 
(
    SELECT split.SplitVal, 
     CHARINDEX(N'|', split.SplitVal) AS [PipeLocation], 
     LEN(split.SplitVal) AS [PairLength] 
    FROM SQL#.String_Split4k(@Sample2, N',', 1) split 
), pieces AS 
(
    SELECT LEFT(kvpairs.SplitVal, (kvpairs.PipeLocation - 1)) AS [Key], 
     RIGHT(kvpairs.SplitVal, (kvpairs.PairLength - kvpairs.PipeLocation)) 
       AS [Value] 
    FROM kvpairs 
) 
SELECT CONVERT(XML, N'<' + pieces.[Key] + N'>' 
       + pieces.[Value] 
       + N'</' + pieces.[Key] + N'>') 
FROM pieces 
FOR XML PATH(''); 

Обратите внимание:

  • Оба примера использует в SQL# библиотеке, которая представляет собой совокупность SQLCLR функций и проков (которые я написал, но функция, показанная здесь, в бесплатной версии) ,

  • Метод RegEx отлично подходит для использования в инструкции SELECT для таблицы, передавая в столбце выражение, подлежащее оценке. Метод Split/CTE должен быть помещен в функцию (встроенный TVF) для использования в запросе через CROSS APPLY.

  • Второй пример, выполняющий разделение, не должен использовать SQLCLR; он может использовать чистый разделитель T-SQL, используя встроенную таблицу таблиц или XML.

+0

, в то время как у меня нет проблем с одним из них, неудачная библиотека SQL # недоступна мне. – DidIReallyWriteThat

+0

@CalvinSmith Нет политики SQLCLR? В любом случае, просто подумал, что я хотел бы упомянуть о возможности. Второй пример, выполняющий разделение, по-прежнему является вариантом, поскольку вы можете использовать чистый разделитель T-SQL, используя встроенную таблицу таблиц или XML. И поэтому вы все равно не будете ограничены количеством элементов. Вариант № 2 не должен использовать SQLCLR. –

Смежные вопросы