Разделение текста или больших двоичных объектов на строки данных и таблицы в SQL Server
Текст в строки
Следуя некоторым из моих других статей о функциях SQL, это функция, которую мы используем как часть кода для поиска в нашей библиотеке документов CMS.
Прежде всего, функция объявляет таблицу, которая будет возвращена позже.
Затем мы удаляем все повторяющиеся разделители, чтобы уменьшить объем возвращаемых записей.
Затем мы перебираем строку и вставляем слово в объявленную таблицу при каждом появлении разделителя, который мы объявляем в начале.
Эта функция использует привязку схемы, поэтому ее можно использовать в других функциях привязки схемы, которые даже могут быть привязаны к таблице.
В SQL Server 2016 была введена встроенная функция STRING_SPLIT, и если у вас есть совместимость выше версии 130, вы можете использовать ее для одного разделителя.
По мере продвижения работы мы превзошли string_split и теперь можем обрабатывать текстовые квалификаторы, даже если они присутствуют только в определенных столбцах.
SQL Code - Basic Function
CREATE FUNCTION [dbo].[TextToRows](@Delim NVARCHAR(10),@Value NVARCHAR(MAX))--Delimeter and Search StringRETURNS @Table TABLE(WordInt BIGINT IDENTITY(1,1) PRIMARY KEY,WordStr NVARCHAR(MAX)) WITH SCHEMABINDING --Return TableAS BEGINSET @Value=LTRIM(RTRIM(@Value))--Trim forward/trailing spacesWHILE (CHARINDEX(@Delim+@Delim,@Value,1)<>0) BEGINSET @Value=REPLACE(@Value,@Delim+@Delim,@Delim)--Remove double delims (if required)...ENDDECLARE @CurPos BIGINTSET @CurPos=0DECLARE @NextPos BIGINTSET @NextPos=CHARINDEX(@Delim,@Value,@CurPos+1)WHILE @NextPos>0 BEGININSERT INTO @Table(WordStr)SELECT REPLACE(SUBSTRING(@Value,@CurPos,(@NextPos-@CurPos)),@Delim,'')--Add first word if existsSET @CurPos=@NextPosSET @NextPos=CHARINDEX(@Delim,@Value,@CurPos+1)ENDINSERT INTO @Table(WordStr) SELECT REPLACE(SUBSTRING(@Value,@CurPos,LEN(@Value)),@Delim,'')--Add last word (or whole word)RETURNENDGOSELECT * FROM TextToRows(',','Gavin,Clayton,Test,Data')
Result
Clayton
Test
Data
New SQL Code - With Text Qualifiers
CREATE FUNCTION dbo.[TextToRowsText](@Delim NVARCHAR(10),@Value NVARCHAR(MAX),@Text NVARCHAR(1))--Delimeter and Search StringRETURNS @Table TABLE(WordInt BIGINT IDENTITY(1,1) PRIMARY KEY,WordStr NVARCHAR(MAX)) --Return TableAS BEGINDECLARE @TextOn INT=(CASE WHEN LEFT(@Value,1)=@Text AND LEN(@Text)>0 THEN 1 ELSE 0 END)DECLARE @NextPos BIGINT=CHARINDEX((CASE WHEN @TextOn=1 THEN @Text+@Delim ELSE @Delim END),@Value,LEN(@Delim)+(@TextOn))WHILE @NextPos>0 BEGININSERT INTO @Table(WordStr) SELECT SUBSTRING(@Value,LEN(@Text)+@TextOn,(@NextPos-(LEN(@Text)+@TextOn)))SET @Value=SUBSTRING(@Value,@NextPos+@TextOn+LEN(@Delim),9999999)SET @TextOn=(CASE WHEN LEFT(@Value,1)=@Text AND LEN(@Text)>0 THEN 1 ELSE 0 END)SET @NextPos=CHARINDEX((CASE WHEN @TextOn=1 THEN @Text+@Delim ELSE @Delim END),@Value,LEN(@Text)+@TextOn)ENDSET @TextOn=(CASE WHEN LEFT(@Value,1)=@Text AND LEN(@Text)>0 THEN 1 ELSE 0 END)IF LEN(@Value)>0 INSERT INTO @Table(WordStr) SELECT SUBSTRING(@Value,LEN(@Text)+@TextOn,(CASE WHEN RIGHT(@Value,1)=@Text THEN LEN(@Value)-(LEN(@Text)+@TextOn) ELSE 9999999 END))RETURNENDGOSELECT * FROM dbo.TextToRowsText(',','Gavin,"Clayton","Test",Data','"')
Использовать с PIVOT
Вы также можете использовать это применительно к самому себе, чтобы разделить несколько разделителей, или с помощью PIVOT, чтобы создать таблицу из вашего набора результатов. Ниже представлена функция с двойным разделением, разделенная на таблицу.
Используя это, вы можете быстро уменьшить количество символов, пересылаемых между компьютерами. При необходимости вы можете использовать разделитель длиной до 10 символов.
Double Delimited & Pivot
DECLARE @Str NVARCHAR(1000)='1;1.2;1.2.3;1.2.3.4'SELECT * FROM (SELECT ttr.WordStr Orig,ttr2.WordInt,ttr2.WordStrFROM dbo.TextToRows(';',@Str) ttrOUTER APPLY dbo.TextToRows('.',ttr.WordStr) ttr2) ttrdPIVOT (MAX(WordStr) FOR WordInt IN ([1],[2],[3],[4])) Piv
Double Delimited Pivot Result
Orig | 1 | 2 | 3 | 4 |
1 | 1 | NULL | NULL | NULL |
1.2 | 1 | 2 | NULL | NULL |
1.2.3 | 1 | 2 | 3 | NULL |
1.2.3.4 | 1 | 2 | 3 | 4 |