Разделить текст по пробелам в SQL Server 2012 - PullRequest
3 голосов
/ 24 марта 2019

Я использую SQL Server 2012, поэтому функция разделения строк недоступна.

Учтите, что у меня есть таблица с именем DISK_VOLUME, в которой только один столбец RESULT и в настоящее время 4 строки:

RESULT
----------------------------------------
P: 220825387008  959589646336  DADOS       
I: 166207356928  959589646336  INDEXS       
E: 636080054272  799165902848  LOG          
C: 462246113280  999651536896

Мне нужен запрос, который разделяет эти строки по пробелам, показывая 4 столбца, например:

Caption  | Space 1      | Space 2        | Volume Name 
---------+--------------+----------------+--------------
P:       | 220825387008 | 959589646336   | DADOS 
I:       | 166207356928 | 959589646336   | INDEXS 
E:       | 636080054272 | 799165902848   | LOG 
C:       | 462246113280 | 999651536896   |

Но нет контроля количества пробелов в строке. Это может иметь как

  • Пространство слова Слово
  • Слово-пространство-пространство-пространство Слово

Это означает, что использование charindex(' ', ini_pos, ini_pos + 1) само по себе не сработает, поскольку я не могу рассчитывать на наличие следующего слова сразу после поиска пробелов.

Итак, в основном я искал любую функцию или комбинацию команд, которая динамически разделяет строку на пробелы (рекурсивная функция, xml, IDK). Все мои попытки сделать это потерпели неудачу.

Ответы [ 2 ]

1 голос
/ 24 марта 2019

Вы можете разбить строку, используя XML.Сначала вам нужно преобразовать строку в XML и заменить пробел на start и end XML tags.

После преобразования строки в XML вы можете использовать XQuery, чтобы получить результат в правильном формате.

Чтобы показать данные в нескольких столбцах, вы можете просто использовать PIVOT

;WITH CTE AS
(
 SELECT 
 F1.results,
 O.splitdata,
 row_number() over(partition by results order by (select 1)) rn FROM
    (
        SELECT *, 
        cast('<X>'+replace(F.results,' ','</X><X>')+'</X>' as XML) as xmlfilter 
        from [YourTableName] F
        )F1
        CROSS APPLY
        ( 
            SELECT fdata.D.value('.','varchar(500)') as splitdata 
            FROM f1.xmlfilter.nodes('X') as fdata(D) 
        ) O
        where splitdata <> ''
    ) 

 select [1] [Caption],[2] [Space1],[3] [Space2], [4] [Volume Name] 
 from CTE c
 PIVOT (max(splitdata) for rn in ([1],[2],[3],[4])) pvt

Online Demo

Выход

+---------+--------------+--------------+-------------+
| Caption | Space1       | Space2       | Volume Name |
+---------+--------------+--------------+-------------+
| C:      | 462246113280 | 999651536896 | NULL        |
+---------+--------------+--------------+-------------+
| E:      | 636080054272 | 799165902848 | LOG         |
+---------+--------------+--------------+-------------+
| I:      | 166207356928 | 959589646336 | INDEXS      |
+---------+--------------+--------------+-------------+
| P:      | 220825387008 | 959589646336 | DADOS       |
+---------+--------------+--------------+-------------+
1 голос
/ 24 марта 2019

Вы можете попытаться создать функцию fn_split.

CREATE FUNCTION fn_split 
( @Words nvarchar(MAX)
, @splitStr varchar(50) 
)
RETURNS @Result_Table TABLE
       (
         [word] nvarchar(max) NULL
       )
BEGIN 
    Declare @TempStr nvarchar(MAX)

    WHILE (CHARINDEX(@splitStr,@Words)>0)
    BEGIN
        Set @TempStr=SUBSTRING(@Words,1,CHARINDEX(@splitStr,@Words)-1)
        Insert into @Result_Table (word) Values (@TempStr)

        Set @Words = REPLACE(@Words,@TempStr+@splitStr,'')
    END/*End While*/

    IF(LEN(RTRIM(LTRIM(@Words)))>0 And CHARINDEX(@splitStr,RTRIM(LTRIM(@Words)))=0) 
    Begin
        Set @TempStr=@Words 

        Insert into @Result_Table (word) Values (@TempStr)

    End 

   RETURN 
END

, затем используйте небольшой навык, пропустите несколько на один пробел на DISK_VOLUME, замените три раза.

В следующем шаге используйте row_number оконную функцию, чтобы получить номер для агрегатной функции условия.

;WITH CTE as(
    SELECT val,word,ROW_NUMBER() OVER(PARTITION BY val order by val) rn
    FROM (
        SELECT replace(replace(replace(DISK_VOLUME,' ','*&'),'&*',''),'*&',' ') val
        FROM T
    ) t1 CROSS APPLY fn_split(t1.val,' ') v
)

SELECT max(CASE WHEN rn = 1 THEN word END) 'Caption',
       max(CASE WHEN rn = 2 THEN word END) 'Space1',
       max(CASE WHEN rn = 3 THEN word END) 'Space 2',
       max(CASE WHEN rn = 4 THEN word END) 'Volume Name '
FROM CTE
GROUP BY val

sqlfiddle

...