在SQL Server 2012上按空格分割文本

时间:2019-03-24 03:50:45

标签: sql sql-server split sql-server-2012 substring

我正在使用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   |

但是无法控制字符串中的空格数量。它可以像

  • 单词空间单词
  • 单词空间space space space Word

这意味着单独使用charindex(' ', ini_pos, ini_pos + 1)是行不通的,因为我不能依靠空格查找后的下一个单词。

因此,基本上我正在寻找的是动态地将行按行分隔的任何函数或命令组合(递归函数,xml,IDK)。我所有的尝试都失败了。

2 个答案:

答案 0 :(得分:1)

您可以尝试创建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

答案 1 :(得分:1)

您可以使用XML分割字符串。您首先需要将字符串转换为XML,并用startend 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       |
+---------+--------------+--------------+-------------+