[英]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.