只是为了看看它是否可以完成,我想出了一个不循环的解决方案。它是基于别人的函数来根据分隔符拆分字符串。
注意:
这要求您提前知道最大令牌长度。该函数将在遇到比指定行长更长的标记时停止返回行。可能还潜伏着其他错误,因此请谨慎使用此代码。
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
它实际上非常快,你可以做一些很酷的事情,比如加入它。这是一个简单的示例,它从表中的每一行中获取第一行:
declare @table table (
id int,
paragraph varchar(7999)
)
insert into @table values (1, '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.')
insert into @table values (2, 'Is there a way to split a string (from a specific column) to n-number chars without breaking words, with each result in its own row?')
select t.id, l.LineNumber, l.Line, len(Line)
from @table t
cross apply SplitLines(t.paragraph, 42, ' ') l
where l.LineNumber = 1