繁体   English   中英

在','和'|'上拆分sql字符串

[英]split sql string on ',' and '|'

我的目标是转换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个块,然后解剖每个块?

您可以使用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 

在这里,我只是改变了你| to ,并一举完成所有分裂,但如果它不是所有偶数对,你可以分两步完成,首先分裂| 然后,

你也可以查看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, @pos-@prevPos)
        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版本,但没有进行太多的比较测试。

只是有选项:-),如果最终目标是将输入字符串转换为XML,则可以使用正则表达式替换来执行此操作,并且它不会受限于任意数量的元素:

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" />

或者,您可以在CTE内的逗号上分割字符串(给出由管道符号分隔的无限数量的键 - 值对),然后在它们的单个分隔符上拆分这些对:

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函数和procs的集合(我写过,但这里显示的函数是免费版本)。

  • RegEx方法可以在针对表的SELECT语句中使用,将列作为要计算的表达式传入。 需要将Split / CTE方法放入函数(内联TVF)中,以便通过CROSS APPLY在查询中使用。

  • 第二个例子,进行拆分,不必使用SQLCLR; 它可以使用内联计数表或XML使用纯T-SQL拆分器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM