【问题标题】:SQL - Separate Out Text From StringSQL - 从字符串中分离出文本
【发布时间】:2016-03-09 21:44:11
【问题描述】:

我有一个包含 2 列的表(在 SQL Server 中)。一列包含多个服务器名称,以波浪号~ 分隔。此列可以包含也可以不包含实际的服务器名称。另一列具有实际的服务器名称。

我正在寻找一种将第一列值分隔到它们自己的分隔列中的方法。别名的数量范围从 1 到 ?。

Server_Alias_Names                              Actual_Server_Name
------------------------------------------------------------
Server1~ROSCO24~Server3~Server4~~~~~            ROSCO24
STEVETESDB26~~~~~~~~~                           STEVETESDB26
RALPHPRD117~RALPHPRD117-adm~Server0025~Server0025a1~Server0025a2~Server0025a3~~~~~        RALPHPRD117
Server1001~Server1001R1~Server1001-adm~~~~~~~   DBTEST1001

我从字符串中提取了前两个服务器,但在接下来的几个服务器上我遇到了问题。任何帮助表示赞赏!!!

SELECT
    LEFT(Server_Alias_Names, CHARINDEX('~', Server_Alias_Names) - 1) as 'First_Server',
SUBSTRING(Server_Alias_Names,len(LEFT(Server_Alias_Names, CHARINDEX('~', Server_Alias_Names)+1)),LEN(LEFT(Server_Alias_Names, CHARINDEX ('~', Server_Alias_Names)))) as 'Second_Server'
FROM 
    TBL_NAME

【问题讨论】:

    标签: sql sql-server substring


    【解决方案1】:

    完成此操作的最简单方法是使用字符串拆分器。 Aaron Bertrand 在这里列出了相当完整的可行选项列表。 http://sqlperformance.com/2012/07/t-sql-queries/split-strings。请注意,这些都没有任何循环或递归。我不太确定你想用这些信息做什么,但你说你只是想解析字符串。

    【讨论】:

      【解决方案2】:
      WITH splitit
      AS
      (
          SELECT Actual_Server_Name,  len(Actual_Server_Name) - len(replace(Actual_Server_Name, '~', '')) as TildaCount,
          CONVERT(XML,'<X><x>'  
          + REPLACE(Server_Alias_Names,'~', '</x><x>') + '</x></X>') AS xmlname
            FROM table
      )
      SELECT Actual_Server_Name,      
             CASE TildaCount > 0 THEN xmlname.value('/X/x[1]','varchar(100)') ELSE '' END AS s1,    
             CASE TildaCount > 1 THEN xmlname.value('/X/x[2]','varchar(100)') ELSE '' END AS s2,    
             CASE TildaCount > 2 THEN xmlname.value('/X/x[3]','varchar(100)') ELSE '' END AS s3,    
             CASE TildaCount > 3 THEN xmlname.value('/X/x[4]','varchar(100)') ELSE '' END AS s4,    
             CASE TildaCount > 4 THEN xmlname.value('/X/x[5]','varchar(100)') ELSE '' END AS s5,    
             CASE TildaCount > 5 THEN xmlname.value('/X/x[6]','varchar(100)') ELSE '' END AS s6,    
             CASE TildaCount > 6 THEN xmlname.value('/X/x[7]','varchar(100)') ELSE '' END AS s7
      FROM splitit
      

      如果你愿意,你也可以从末尾删除多余的 ~,但我认为即使你不这样做也可以。

      【讨论】:

      • 如果我运行您的代码,我会收到以下错误:Msg 2389, Level 16, State 1, Line 11 XQuery [splitit.xmlname.value()]: 'value()' requires a singleton (或空序列),找到类型为“xdt:untypedAtomic *”的操作数
      • @JeremyF。这意味着您有一些元素少于 7 个的项目——我将编写一些如何解决的示例代码......但它不会被测试......
      【解决方案3】:

      @Hogan - 我最终将您的脚本与@Sean Lange 在评论中提供的链接的一些帮助结合起来。这是我想出的。

      WITH splitit
      AS
      (
      SELECT 
      y.i.value('(./text())[1]', 'nvarchar(4000)') as Separated_Server,
      Actual_Server_Name
      FROM 
                ( 
                  SELECT x = CONVERT(XML, '<i>' 
                  + REPLACE(Server_Alias_Names,'~', '</i><i>') 
                  + '</i>').query('.')
                  , Actual_Server_Name
                  FROM TBL_NAME
                ) as a cross apply x.nodes('i') as y(i)
      )
      
      SELECT DISTINCT
      Actual_Server_Name,
      Separated_Server
      FROM splitit
      Where Separated_Server is not null
      ORDER BY 1,2
      
      --Some of the separated items were also sorted by a comma so I added another step to separate those as well.
      --Uncomment the code below for an additional and replace the comma after Separated_Server with the special character you want to use for separation
      
      --,splitit_2
      --AS
      --(
      --SELECT distinct
      --ServerName,
      --y.i.value('(./text())[1]', 'nvarchar(4000)') as Server_Alias
      
      --FROM 
      --          ( 
      --          SELECT x = CONVERT(XML, '<i>' 
      --          + REPLACE(Separated_Server,',', '</i><i>') 
      --          + '</i>').query('.')
      --          ,[ServerName]
      --          FROM splitit
      --        ) as a cross apply x.nodes('i') as y(i)
      --)
      
      
      --SELECT DISTINCT
      --Actual_Server_Name,
      --Separated_Server
      --FROM splitit_2
      --Where Separated_Server is not null
      --ORDER BY 1,2
      

      【讨论】:

      • 这与你要求的完全不同——你要求的是一个有 7 列的结果。希望我知道这就是你想要的……容易多了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-27
      • 1970-01-01
      • 1970-01-01
      • 2011-06-18
      • 2019-11-24
      • 1970-01-01
      相关资源
      最近更新 更多