【问题标题】:SQL Server 2005 Using CHARINDEX() To split a stringSQL Server 2005 使用 CHARINDEX() 分割字符串
【发布时间】:2013-07-09 18:40:28
【问题描述】:

如何根据 '-' 字符拆分以下字符串?

如果我有这个字符串:LD-23DSP-1430

我怎么能把它分成这样的单独的列:

LD        23DSP       1430

另外,如果我需要的话,有没有办法将每个字符分成一个单独的字段(没有“-”)?我正在尝试找到一种方法将每个字母替换为 NATO 字母表。

所以这将是...... Lima Delta 23 Delta Sierra Papa 14 30.... 在一个领域。

我知道我可以像这样得到左侧:

LEFT(@item, CHARINDEX('-', @item) - 1)

【问题讨论】:

  • 可以使用substring函数,用第一次、第二次、第三次点击的charindex等增加起始索引。
  • @jpw 他如何找到第二个破折号的字符索引?
  • @RaduGheorghiu 通过在从第一个破折号的 charindex + 1 开始的子字符串中搜索破折号。
  • “删除”和“删除”不是北约字母表 (FTFY) 的一部分。另外,数字不应该像“二三”而不是“二十三”吗?
  • @user2531854 你应该看看Split strings the right way – or the next best way,由 SQL 大师 Aaron Bertrand 编写。它为分裂问题提供了几个很好的解决方案。

标签: sql sql-server-2005


【解决方案1】:

我不会说这很容易或显而易见,但只需两个连字符,您就可以反转字符串,而且不会太难:

with t as (select 'LD-23DSP-1430' as val)
select t.*,
       LEFT(val, charindex('-', val) - 1),
   SUBSTRING(val, charindex('-', val)+1, len(val) - CHARINDEX('-', reverse(val)) - charindex('-', val)),
       REVERSE(LEFT(reverse(val), charindex('-', reverse(val)) - 1))
from t;

除此之外,您可能还想改用split()

【讨论】:

    【解决方案2】:

    这里有一个小函数可以为你做“北约编码”:

    CREATE FUNCTION dbo.NATOEncode (
       @String varchar(max)
    )
    RETURNS TABLE
    WITH SCHEMABINDING
    AS
    RETURN (
       WITH L1 (N) AS (SELECT 1 UNION ALL SELECT 1),
       L2 (N) AS (SELECT 1 FROM L1, L1 B),
       L3 (N) AS (SELECT 1 FROM L2, L2 B),
       L4 (N) AS (SELECT 1 FROM L3, L3 B),
       L5 (N) AS (SELECT 1 FROM L4, L4 C),
       L6 (N) AS (SELECT 1 FROM L5, L5 C),
       Nums (Num) AS (SELECT Row_Number() OVER (ORDER BY (SELECT 1)) FROM L6)
       SELECT
          NATOString = Substring((
             SELECT
                Convert(varchar(max), ' ' + D.Word)
             FROM
                Nums N
                INNER JOIN (VALUES
                   ('A', 'Alpha'),
                   ('B', 'Beta'),
                   ('C', 'Charlie'),
                   ('D', 'Delta'),
                   ('E', 'Echo'),
                   ('F', 'Foxtrot'),
                   ('G', 'Golf'),
                   ('H', 'Hotel'),
                   ('I', 'India'),
                   ('J', 'Juliet'),
                   ('K', 'Kilo'),
                   ('L', 'Lima'),
                   ('M', 'Mike'),
                   ('N', 'November'),
                   ('O', 'Oscar'),
                   ('P', 'Papa'),
                   ('Q', 'Quebec'),
                   ('R', 'Romeo'),
                   ('S', 'Sierra'),
                   ('T', 'Tango'),
                   ('U', 'Uniform'),
                   ('V', 'Victor'),
                   ('W', 'Whiskey'),
                   ('X', 'X-Ray'),
                   ('Y', 'Yankee'),
                   ('Z', 'Zulu'),
                   ('0', 'Zero'),
                   ('1', 'One'),
                   ('2', 'Two'),
                   ('3', 'Three'),
                   ('4', 'Four'),
                   ('5', 'Five'),
                   ('6', 'Six'),
                   ('7', 'Seven'),
                   ('8', 'Eight'),
                   ('9', 'Niner')
                ) D (Digit, Word)
                   ON Substring(@String, N.Num, 1) = D.Digit
             WHERE
                N.Num <= Len(@String)
             FOR XML PATH(''), TYPE
          ).value('.[1]', 'varchar(max)'), 2, 2147483647)
    );
    

    这个函数甚至可以处理很长的字符串,并且性能非常好(我对一个 100,000 个字符的字符串运行它,它在 589 毫秒内返回)。这是一个如何使用它的示例:

    SELECT NATOString FROM dbo.NATOEncode('LD-23DSP-1430');
    -- Output: Lima Delta Two Three Delta Sierra Papa One Four Three Zero
    

    我故意将其设为表值函数,因此如果您一次针对多行运行它,它可以内联到查询中,只需使用 CROSS APPLY 或将上面的示例括在括号中以将其用作SELECT子句(可以在函数参数位置放一个列名)。

    【讨论】:

    • 很酷的功能。我似乎无法在 SQL 2005 上运行它。我得到 Msg 156, Level 15, State 1, Procedure NATOEncode, Line 21 关键字“VALUES”附近的语法不正确。
    • 在 SQL 2005 中将其更改为 INNER JOIN (SELECT 'A', 'Alpha' UNION ALL SELECT 'B', 'Beta' UNION ALL ...)
    • 北约字母表中不使用九,因为它可能与德语 (Nein) 中的“不”混淆,听起来像九。北约字母表中数字 9 的正确等价物是“niner”。干杯!
    • @levteck 你说的太对了!我什至知道这一点,但我猜只是冲得太快了。已修复,谢谢!
    【解决方案3】:

    尝试以下查询:

    DECLARE @item VARCHAR(MAX) = 'LD-23DSP-1430'
    
    SELECT
    SUBSTRING( @item, 0, CHARINDEX('-', @item)) ,
    SUBSTRING(
                   SUBSTRING( @item, CHARINDEX('-', @item)+1,LEN(@ITEM)) ,
                   0 ,
                   CHARINDEX('-', SUBSTRING( @item, CHARINDEX('-', @item)+1,LEN(@ITEM)))
                  ),
    REVERSE(SUBSTRING( REVERSE(@ITEM), 0, CHARINDEX('-', REVERSE(@ITEM))))
    

    【讨论】:

    • 感谢您的回答!另一个问题。如果一个项目有多个破折号怎么办。所以它可能是 LD-23DSP-MF-1430 有没有办法计算有多少破折号并将每个部分分解为一个字段?
    【解决方案4】:
        USE [master]
        GO
        /******  this function returns Pakistan where as if you want to get ireland simply replace (SELECT SUBSTRING(@NEWSTRING,CHARINDEX('$@$@$',@NEWSTRING)+5,LEN(@NEWSTRING))) with
    SELECT @NEWSTRING = (SELECT SUBSTRING(@NEWSTRING, 0,CHARINDEX('$@$@$',@NEWSTRING)))******/
        SET ANSI_NULLS ON
        GO
        SET QUOTED_IDENTIFIER ON
        GO
        CREATE FUNCTION [dbo].[FN_RETURN_AFTER_SPLITER] 
        (  
         @SPLITER varchar(max))
        RETURNS VARCHAR(max)
        AS 
        BEGIN
    
        --declare @testString varchar(100),
        DECLARE @NEWSTRING VARCHAR(max) 
        -- set @teststring = '@ram?eez(ali)'
         SET @NEWSTRING = @SPLITER ; 
    
        SELECT @NEWSTRING = (SELECT SUBSTRING(@NEWSTRING,CHARINDEX('$@$@$',@NEWSTRING)+5,LEN(@NEWSTRING)))
        return @NEWSTRING 
        END
        --select [dbo].[FN_RETURN_AFTER_SPLITER]  ('Ireland$@$@$Pakistan')
    

    【讨论】:

      【解决方案5】:
      Create FUNCTION [dbo].[fnSplitString] 
      ( 
          @string NVARCHAR(200), 
          @delimiter CHAR(1) 
      ) 
      RETURNS @output TABLE(splitdata NVARCHAR(10) 
      ) 
      BEGIN 
          DECLARE @start INT, @end INT 
          SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
          WHILE @start < LEN(@string) + 1 BEGIN 
              IF @end = 0  
                  SET @end = LEN(@string) + 1
      
              INSERT INTO @output (splitdata)  
              VALUES(SUBSTRING(@string, @start, @end - @start)) 
              SET @start = @end + 1 
              SET @end = CHARINDEX(@delimiter, @string, @start)
      
          END 
          RETURN 
      
      END**strong text**
      

      【讨论】:

        【解决方案6】:
        DECLARE @variable VARCHAR(100) = 'LD-23DSP-1430';
        WITH    Split
              AS ( SELECT   @variable AS list ,
                            charone = LEFT(@variable, 1) ,
                            R = RIGHT(@variable, LEN(@variable) - 1) ,
                            'A' AS MasterOne
                   UNION ALL
                   SELECT   Split.list ,
                            LEFT(Split.R, 1) ,
                            R = RIGHT(split.R, LEN(Split.R) - 1) ,
                            'B' AS MasterOne
                   FROM     Split
                   WHERE    LEN(Split.R) > 0
                 )
        SELECT  *
        FROM    Split
        OPTION  ( MAXRECURSION 10000 );
        

        【讨论】:

        • 嗨@Kandarp Patel,您的解决方案不符合问题要求。
        猜你喜欢
        • 1970-01-01
        • 2017-07-28
        • 1970-01-01
        • 1970-01-01
        • 2021-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多