それができるかどうかを確認するために、ループしないソリューションを思いつきました。区切り文字に基づいて文字列を分割するのは、他の誰かの機能に基づいています。
注:
これには、トークンの最大長を事前に知っておく必要があります。この関数は、指定された行の長さよりも長いトークンに遭遇すると、行を返すのを停止します。おそらく他にもバグが潜んでいるので、このコードは慎重に使用してください。
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