【发布时间】:2020-05-11 04:10:13
【问题描述】:
好的,我一直在到处寻找正确的语法。 假设我有一串长度未知的字符串 即“敏捷的棕色狐狸跳过懒惰的狗。敏捷的棕色狐狸跳过了懒狗。敏捷的棕色狐狸跳过了懒狗。敏捷的棕色狐狸跳过了懒狗。敏捷的棕色狐狸跳过了懒惰的狗。'
我需要将它分成最多 35 个字符的块,每个字符都像:'The quick brown fox jumps over the' 空格是分隔符。
规则是:
1 - 每个块不超过 35 个字符
2 - 不要拆分单词。
2.1 - 如果组合长度大于 35,则返回直到找到长度低于 35 的第一个空格并将其剪掉。
3 - 如果需要,结果集必须返回一个包含 5 个值(由字符串块组成)和一个表示多条记录结果的行号的表。 (见下表)
也就是说,如果一个字符串分成 5 35 个字符块,一条记录返回 任何多余的溢出到 5 组中的更多行
________________________________________________________________________________________________________________________________________________________________________________|
|level | Val1 |Val2 | Val3 | Val4 | Val5 |
________________________________________________________________________________________________________________________________________________________________________________|
| 1 |The quick brown fox jumps over the | lazy dog. The quick brown fox | jumps over the lazy dog. The | quick brown fox jumps over the | lazy dog. The quick brown fox |
| 2 | jumps over the lazy dog. The | quick brown fox jumps over the| lazy dog. |NULL | NULL |
________________________________________________________________________________________________________________________________________________________________________________|
我在这里找到了一些类似工作的代码,但我无法将结果限制为 35 个字符块
它的作用是: 获取字符串中的分隔符数(空格数) 比使用 CTE 将所有内容拆分到表中。 而不是全部连接回来。但是,在“Splitvalues”cte 中,如果我将 mainLevel 分成 5 个,它可以工作,但不是按长度加入,而是按 5 组加入 而且我仍然不知道如何将结果转为 6 列,如所述。
DECLARE @ColumnLen INT = 35
,@BNotAllowNullinValue1 BIT = 1
,@Delim VARCHAR(5) = SPACE(1)
,@DelimCount INT
,@OriginalStr NVARCHAR(MAX) = 'The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.'
,@ReturnColumnCount INT = 5
SET @OriginalStr = @OriginalStr + @Delim
SET @DelimCount = ((LEN(@OriginalStr + '|')-1) - (LEN(REPLACE(@OriginalStr + '|',@Delim,''))-1)) / LEN(LTRIM(RTRIM(@Delim)) + '|')
---- test data
;WITH Splitvalues(SplitValue ,MainLevel ,ProcessLevel,LastPos,Original)
AS (SELECT TOP 1 LTRIM(RTRIM(SUBSTRING(@OriginalStr,1,ABS(CHARINDEX(@Delim,@OriginalStr,1)))))
,1 as MainLevel
,1 as ProcessLevel
,CHARINDEX(@Delim,@OriginalStr,1 + 1) AS LastPos
,@OriginalStr
UNION ALL
SELECT LTRIM(RTRIM(SUBSTRING(@OriginalStr,LastPos + 1,ABS((CHARINDEX(@Delim,@OriginalStr,LastPos + 1) - LastPos)))))
,CASE (ProcessLevel % 5) WHEN 0 THEN MainLevel +1 ELSE MainLevel END as MainLevel
,ProcessLevel + 1 as ProcessLevel
,CHARINDEX(@Delim,@OriginalStr,LastPos + 1) AS LastPos
,@OriginalStr
FROM Splitvalues
WHERE ProcessLevel <= @DelimCount
AND ISNULL(LTRIM(RTRIM(SUBSTRING(@OriginalStr,LastPos + 1,ABS((CHARINDEX(@Delim,@OriginalStr,LastPos + 1) - LastPos))))),'') <> '')
---- actual query;
,cte(MainLevel,ProcessLevel,combined,rn)
AS (SELECT MainLevel,ProcessLevel,Splitvalue ,rn = ROW_NUMBER() OVER(PARTITION BY MainLevel ORDER BY MainLevel,ProcessLevel)FROM Splitvalues)
,cte2(MainLevel,ProcessLevel ,finalstatus ,rn)
AS (SELECT MainLevel,cte.ProcessLevel ,CONVERT(VARCHAR(MAX),combined) ,1 FROM cte WHERE rn = 1
UNION ALL
SELECT cte2.MainLevel,cte2.ProcessLevel +1 ,CONVERT(VARCHAR(MAX),cte2.finalstatus + @Delim + cte.combined+ @Delim )
,cte2.rn + 1
FROM cte2
INNER JOIN cte ON cte.MainLevel = cte2.MainLevel AND cte.rn = cte2.rn + 1
)
SELECT MainLevel,MAX(finalstatus),LEN(MAX(finalstatus)+'|')
FROM cte2
GROUP BY MainLevel
感谢大家的帮助。
【问题讨论】:
-
这里添加最终代码的规则是什么?我应该使用回答我的 onw 问题吗?即使我接受了其中一个答案?