将SQL Server中的字符串拆分为最大长度,并将每个字符串作为行返回

将SQL Server中的字符串拆分为最大长度,并将每个字符串作为行返回,sql,sql-server,tsql,Sql,Sql Server,Tsql,有没有一种方法可以将字符串(从特定列)拆分为n个数字字符而不打断单词,每个结果都在自己的行中 例如: 2012-04-24 Change request #3 for the contract per terms and conditions and per John Smith in the PSO department Customer states terms should be Net 60 not Net 30. Please review signed contract for

有没有一种方法可以将字符串(从特定列)拆分为n个数字字符而不打断单词,每个结果都在自己的行中

例如:

2012-04-24 Change request #3 for the contract per terms and conditions and per John Smith in the PSO department  Customer states terms should be Net 60 not Net 30.  Please review signed contract for this information.
结果:

2012-04-24 Change request #3 for the contract per terms and conditions and per John Smith in the
PSO department  Customer states terms should be Net 60 not Net 30.
Please review signed contract for this information.

我知道我可以使用charindex查找最后一个空格,但我不确定如何获取剩余的空格并将其作为行返回。

尝试类似的方法。可能您可以创建以下实现的SQL函数

DECLARE @Str VARCHAR(1000)
SET @Str = '2012-04-24 Change request #3 for the contract per terms and conditions and per John Smith in the PSO department  Customer states terms should be Net 60 not Net 30.  Please review signed contract for this information.'

DECLARE @End INT
DECLARE @Split INT

SET @Split = 100

declare @SomeTable table
(
  Content varchar(3000)
)


WHILE (LEN(@Str) > 0)
BEGIN
    IF (LEN(@Str) > @Split)
    BEGIN
        SET @End = LEN(LEFT(@Str, @Split)) - CHARINDEX(' ', REVERSE(LEFT(@Str, @Split)))
        INSERT INTO @SomeTable VALUES (RTRIM(LTRIM(LEFT(LEFT(@Str, @Split), @End))))
        SET @Str = SUBSTRING(@Str, @End + 1, LEN(@Str))
    END
    ELSE
    BEGIN
        INSERT INTO @SomeTable VALUES (RTRIM(LTRIM(@Str)))
        SET @Str = ''
    END
END

SELECT *
FROM @SomeTable
输出如下:

2012-04-24 Change request #3 for the contract per terms and conditions and per John Smith in the
PSO department  Customer states terms should be Net 60 not Net 30.  Please review signed contract
for this information.

我知道这有点晚,但递归cte将允许实现这一点


您还可以使用包含一系列数字的种子表作为开始索引的乘数输入子字符串。

为了看看是否可以这样做,我提出了一个不循环的解决方案。根据分隔符拆分字符串是基于

注意: 这要求您提前知道最大令牌长度。当遇到超过指定行长度的令牌时,函数将停止返回行。可能还有其他潜在的bug,所以请谨慎使用此代码

CREATE FUNCTION SplitLines
(
    @pString    VARCHAR(7999),
    @pLineLen   INT,
    @pDelim     CHAR(1)
)
RETURNS TABLE
   WITH SCHEMABINDING
AS  
RETURN
WITH
      E1(N) AS ( --=== Create Ten 1's
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 --10
               ),
      E2(N) AS (SELECT 1 FROM E1 a, E1 b),   --100
      E4(N) AS (SELECT 1 FROM E2 a, E2 b),   --10,000
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT N)) FROM E4),
lines AS (
  SELECT TOP 1
         1 as LineNumber,
         ltrim(rtrim(SUBSTRING(@pString, 1, N))) as Line,
         N + 1 as start
  FROM cteTally
  WHERE N <= DATALENGTH(@pString) + 1
    AND N <= @pLineLen + 1
    AND SUBSTRING(@pString + @pDelim, N, 1) = @pDelim
  ORDER BY N DESC
UNION ALL
  SELECT LineNumber, Line, start
  FROM (
    SELECT LineNumber + 1 as LineNumber,
           ltrim(rtrim(SUBSTRING(@pString, start, N))) as Line,
           start + N + 1 as start,
           ROW_NUMBER() OVER (ORDER BY N DESC) as r
    FROM cteTally, lines
    WHERE N <= DATALENGTH(@pString) + 1 - start
      AND N <= @pLineLen
      AND SUBSTRING(@pString + @pDelim, start + N, 1) = @pDelim
  ) A
  WHERE r = 1
)
SELECT LineNumber, Line
FROM lines

我读了一些文章,其中每一篇都有错误或性能不好,或者没有在我们想要的小块或大块中工作。你可以阅读我的评论,甚至在这篇文章下面的任何答案。最后,我找到了一个好答案,并决定在这个问题上与大家分享。我没有在各种场景中检查性能,但我认为这是可以接受的,并且对于大小块长度都可以正常工作。 代码如下:

CREATE function SplitString
(   
    @str varchar(max),
    @length int
)
RETURNS @Results TABLE( Result varchar(50),Sequence INT ) 
AS
BEGIN

DECLARE @Sequence INT 
SET @Sequence = 1

    DECLARE @s varchar(50)
    WHILE len(@str) > 0
    BEGIN
        SET @s = left(@str, @length)
        INSERT @Results VALUES (@s,@Sequence)

        IF(len(@str)<@length)
        BREAK

        SET @str = right(@str, len(@str) - @length)
        SET @Sequence = @Sequence + 1
    END
    RETURN 
END
创建函数拆分字符串
(   
@str varchar(最大值),
@长度整数
)
返回@Results表(Result varchar(50),Sequence INT)
作为
开始
声明@Sequence INT
设置@Sequence=1
声明@s varchar(50)
而len(@str)>0
开始
设置@s=left(@str,@length)
插入@Results值(@s,@Sequence)

IF(len(@str)查看我在这里找到的PrintMax的代码……它查找换行符,但您也可以轻松查找空格。看看Jeff Moden的Split8k函数。这可能会被修改以满足您的需要。您可以始终通过SQL CLR UDF使用.NET正则表达式。我不希望打印它,我希望它作为记录中的单独行返回设置。这太慢了,小尺寸也没用。例如,我想每3个字符拆分一次。谢谢……这是你需要放在后口袋里的烹饪书片段之一。我用它作为我需要的东西的基础,但在处理这个问题时也学到了很多。一个大错误。尝试将pLineLen设置为小值,例如5和你会看到它无法得到结果。我将其与可变长度作为pString进行了对比,发现当pString足够长时,这对pLineLen=>11有效,并且可以通过pString长度进行更改,但在任何长度下都不能将pLineLen设置为小于11。这是一个很大的问题,我认为在大多数情况下都是无用的。经过一点实验,我认为
@pLineLen
需要设置为至少最大的令牌大小加上2。这是有意义的,因为否则会将一个单词一分为二。在上面的示例中,“信息”长度为12,因此需要将
@pLineLen
设置为至少14才能获取所有内容。@Bret,感谢您指出这一点。我修复了代码中的一些错误,因此现在它应该可以正常工作了(大部分)正确,只要
@pLineLen
至少与最大令牌长度一样大。@Chris我在信息安全网站上回答了一个问题,因为没有详细解释答案,甚至我还额外写了一些有用的链接,所以得到了5个减分。如果没有解释、代码、示例和链接,你的答案就没有用处。我没有在其中减去点,但是回答问题时请小心并尽最大努力。@Q老师我感谢您的评论,真的希望有时间对我的答案进行完整的解释-不幸的是,发布答案基本上是一种不用感谢的嗜好。在这种情况下,我费心回答,因为我认为提出不同的观点会很有用,我认为Chad Henderson提供了一个答案,之后给出了一个CTE示例。我个人认为,对于误导性或错误的答案,应该保留否定票。根据我收到的票数,我的答案没有用处,也没有错误。@ChrisMoutray我看到了你的好主意,并试图帮助你。我只是想提醒你,因为我的经验。你能想象-5分吗?:)最后一位专家用户决定删除答案,甚至我也写了新的答案并给出了完整的解释没有一分+1:)你可以看看这个来了解我的诚实:无论如何,我感谢你的尝试和在这里。这并没有回答OP的问题,因为它没有保留文字(即,如果有一个单词位于50个字符处,它会将其切成两半,而不是将整个单词移到下一行)。但是……这正好是我所需要的。:@Keiki谢谢你的注意,我会尽快检查。
CREATE function SplitString
(   
    @str varchar(max),
    @length int
)
RETURNS @Results TABLE( Result varchar(50),Sequence INT ) 
AS
BEGIN

DECLARE @Sequence INT 
SET @Sequence = 1

    DECLARE @s varchar(50)
    WHILE len(@str) > 0
    BEGIN
        SET @s = left(@str, @length)
        INSERT @Results VALUES (@s,@Sequence)

        IF(len(@str)<@length)
        BREAK

        SET @str = right(@str, len(@str) - @length)
        SET @Sequence = @Sequence + 1
    END
    RETURN 
END