如何使用SQL Server将“01020304”更改为“01,02,03,04”?

如何使用SQL Server将“01020304”更改为“01,02,03,04”?,sql,sql-server,tsql,split,Sql,Sql Server,Tsql,Split,给定以下SQL,如何将@x中的值从01020304更改为01,02,03,04 一种方法是递归CTE: with cte as ( select convert(varchar(max), '01020304') as rest, convert(varchar(max), '') as new_str, 1 as lev union all select stuff(rest, 1, 2, '') as rest, concat(new_str, ',',

给定以下SQL,如何将@x中的值从01020304更改为01,02,03,04


一种方法是递归CTE:

with cte as (
      select convert(varchar(max), '01020304') as rest, convert(varchar(max), '') as new_str, 1 as lev
      union all
      select stuff(rest, 1, 2, '') as rest, concat(new_str, ',', left(rest, 2)), lev + 1
      from cte
      where rest > ''
     )
select top (1) stuff(new_str, 1, 1, '')
from cte
order by lev desc;
他是一把小提琴

如果字符串可以包含100多个元素,则需要添加选项maxrecursive 0


毫无疑问,我假设您的输入或多或少是相同的。

虽然@GordonLinoff的答案可能是最正确、最通用的,但根据@x格式的限制,还有更简单的选择

例如:

DECLARE @y nvarchar(100) = TRIM( ',' FROM REPLACE( @x, '0', ',0' ) )
或:


如果可能的话,我倾向于避免递归CTE。对于这样的一个小集合,它实际上没有什么区别,但用于增量的递归cte实际上仍然是RBAR操作

我更喜欢用计分表来计算这类事情。如果您有一个较长的输入字符串,则需要使用较大的理货表,但这不是什么大问题。对于这篇文章,我只是使用了一个内联的

declare @x varchar(256) = '01020304'

declare @result nvarchar(100) = ''
;
with E1(N) as
(
    select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)
),
cteTally(N) AS 
(
    SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E1
)

select @result = @result + substring(@x, t.N, 1) + case when t.N % 2 = 0 and t.N < len(@x) then ',' else '' end
from cteTally t
where t.N <= len(@x)
order by t.N

select @result

另一个解决方案是使用sql server 2017最新函数的litle摘要

DECLARE @x NVARCHAR(MAX) = '01020304'

DECLARE @seperator NVARCHAR(MAX) = '0'

SELECT STRING_AGG(@seperator+value,',')
FROM string_split(@x, @seperator) 
WHERE value <> ''

基本上,它使用分隔符,然后将其添加到值中。使用string agg创建字符串

输入是否总是8个字符长?你会遇到010202040506或1112131145吗?我认为你选择这种方法是为了好玩:P@Dai . . . 你可能是对的。但这似乎是一个合理的方法。谢谢你,戈登。这很有效。@Dai。对SQLServer对递归CTE中的类型过于挑剔。你自己检查一下。戈登,这是停止使用它们并使用计数的另一个很好的理由。提供了简短而好的答案。这适用于样本数据,但我高度怀疑真实数据是否如此简单,这意味着这可能行不通。@SeanLange:也许吧。我假设输入/输出基于问题。很高兴有人发布了一个非迭代的解决方案:From:输出行可以是任意顺序。顺序不能保证与输入字符串中子字符串的顺序匹配。
DECLARE @y nvarchar(100) = ''

DECLARE @idx int = CHARINDEX( '0', @x )
WHILE @idx > 0
BEGIN;

    SET @y = @y + ',' + SUBSTRING( @x, @idx, 2 )

    SET @idx =  CHARINDEX( '0', @x, @idx + 1 )

END;
declare @x varchar(256) = '01020304'

declare @result nvarchar(100) = ''
;
with E1(N) as
(
    select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)
),
cteTally(N) AS 
(
    SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E1
)

select @result = @result + substring(@x, t.N, 1) + case when t.N % 2 = 0 and t.N < len(@x) then ',' else '' end
from cteTally t
where t.N <= len(@x)
order by t.N

select @result
DECLARE @x NVARCHAR(MAX) = '01020304'

DECLARE @seperator NVARCHAR(MAX) = '0'

SELECT STRING_AGG(@seperator+value,',')
FROM string_split(@x, @seperator) 
WHERE value <> ''