[英]Split string and fold in T-SQL
Is it possible to split a delimited string and then 'fold' the delimited parts such that the result is a string containing all possible 'paths'?是否可以分割一个分隔的字符串,然后“折叠”分隔的部分,这样结果是一个包含所有可能的“路径”的字符串? I'm looking to purely use built-in functions if possible without resorting to recursive CTEs, etc.
如果可能的话,我希望纯粹使用内置函数而不诉诸递归 CTE 等。
This is a common functional pattern known as scan/fold.这是一种常见的功能模式,称为扫描/折叠。 Wondering if T-SQL has a similar pattern.
想知道 T-SQL 是否有类似的模式。
Example例子
FOLD('A|B|C|D') = '[A],[A|B],[A|B|C],[A|B|C|D]'
EDIT: The order of the substrings must remain the same in the result.编辑:结果中子字符串的顺序必须保持不变。 The target SQL version is Azure SQL.
目标 SQL 版本是 Azure SQL。
if you have sql-server-2017 you can use STRING_AGG
and STRING_SPLIT
如果你有 sql-server-2017 你可以使用
STRING_AGG
和STRING_SPLIT
declare @text VARCHAR(MAX) ='A|B|C|D'
declare @result VARCHAR(MAX) = ''
SELECT @result = @result + ',[' + STRING_AGG(X.value, '|') + ']' FROM
STRING_SPLIT(@text ,'|') X
INNER JOIN STRING_SPLIT(@text ,'|') Y
ON X.value <= Y.Value
GROUP BY Y.Value
SET @result = STUFF(@result,1,1,'')
print @result
Result:结果:
[A],[A|B],[A|B|C],[A|B|C|D]
As I note in the comments, STRING_SPLIT
has a big caveat in the documentation :正如我在评论中所指出的,
STRING_SPLIT
在文档中有一个很大的警告:
The order is not guaranteed to match the order of the substrings in the input string.
该顺序不能保证与输入字符串中子字符串的顺序匹配。
As a result, you're safer off using a function that gives you the ordinal position.因此,使用为您提供序数位置的函数会更安全。 In this case I use
DelimitedSplit8K_LEAD
and then assume you are using SQL Server 2017+:在这种情况下,我使用
DelimitedSplit8K_LEAD
,然后假设您使用的是 SQL Server 2017+:
DECLARE @YourString varchar(20) = 'A|B|C|D';
WITH Splits AS(
SELECT DS.ItemNumber,
DS.Item
FROM dbo.DelimitedSplit8K_LEAD(@YourString,'|') DS),
Groups AS(
SELECT S1.ItemNumber,
CONCAT('[',STRING_AGG(S2.Item,'|') WITHIN GROUP (ORDER BY S2.ItemNumber),']') AS Agg
FROM Splits S1
JOIN Splits S2 ON S1.ItemNumber >= S2.ItemNumber
GROUP BY S1.ItemNumber)
SELECT STRING_AGG(Agg,',') WITHIN GROUP (ORDER BY ItemNumber)
FROM Groups;
If you aren't on SQL Server 2017+, you'll need to use the "old" FOR XML PATH
(and STUFF
) method.如果您不在 SQL Server 2017+ 上,则需要使用“旧”
FOR XML PATH
(和STUFF
)方法。
Just in case you don't want (or can't use) that SUPER DelimitedSplit8K_LEAD
, here is an XML approach that will maintain the sequence以防万一您不想要(或不能使用) SUPER
DelimitedSplit8K_LEAD
,这里有一种 XML 方法可以维护序列
Example例子
Declare @S varchar(max) = 'A|B|C|D'
;with cte as (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(@S,'|','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
), cte1 as (
Select *
,Comb ='['+stuff((select '|' +RetVal From cte Where RetSeq<=A.RetSeq Order By RetSeq For XML Path ('')),1,1,'') +']'
From cte A
Group By RetSeq,RetVal
)
Select NewValue = stuff((select ',' +Comb From cte1 Order By RetSeq For XML Path ('')),1,1,'')
Returns退货
NewValue
[A],[A|B],[A|B|C],[A|B|C|D]
Starting with v2016 there is JSON, which allows for a position-safe splitter using a JSON array.从 v2016 开始,有 JSON,它允许使用 JSON 数组的位置安全拆分器。 The path can be built with a recursive CTE:
可以使用递归 CTE 构建路径:
DECLARE @yourString VARCHAR(MAX) ='A|B|C|D';
WITH cte AS
(
SELECT A.[key] AS ItmIndex
,A.[value] AS ItmVal
FROM OPENJSON(CONCAT('["',REPLACE(@yourString,'|','","'),'"]')) A
)
,rcte AS
(
SELECT ItmIndex, ItmVal
,CAST(ItmVal AS VARCHAR(MAX)) AS Result
FROM cte
WHERE ItmIndex=0
UNION ALL
SELECT cte.ItmIndex, cte.ItmVal
,CAST(CONCAT(rcte.Result,'|',cte.ItmVal) AS VARCHAR(MAX))
FROM cte
INNER JOIN rcte ON cte.ItmIndex=rcte.ItmIndex+1
)
SELECT * FROM rcte;
The idea in short:简而言之这个想法:
STRING_SPLIT()
).STRING_SPLIT()
除外)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.