【问题标题】:Split text by space on SQL Server 2012在 SQL Server 2012 上按空格分割文本
【发布时间】:2019-08-14 16:15:25
【问题描述】:

我使用的是 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)。我所有的尝试都失败了。

【问题讨论】:

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


    【解决方案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       |
    +---------+--------------+--------------+-------------+
    

    【讨论】:

    • 完美!这正是我想要的,谢谢!
    【解决方案2】:

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

    【讨论】:

    • 虽然我更喜欢上面的XML解决方案,但这也行得通,谢谢!
    猜你喜欢
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 2018-03-22
    • 2016-05-26
    • 2013-10-11
    相关资源
    最近更新 更多