【问题标题】:Split numbers from string从字符串中拆分数字
【发布时间】:2015-01-26 09:35:43
【问题描述】:

我的桌子是这样的

4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione
10-Contrassegno
12-Documenti di annullo polizza-10-Contrassegno
10-Contrassegno
12-Documenti di annullo polizza-10-Contrassegno

我想把每一行都拆分成这样

4-3-2
10
12-10
10
12-10

【问题讨论】:

  • 你的意思是从字符串中提取数字吗?
  • 您是否尝试搜索类似的问题,因为有很多这样的问题..
  • @SubqueryCrunch 是对的 - 有很多类似的问题 - herehere 以及更多使用简单搜索找到的问题。

标签: sql sql-server tsql


【解决方案1】:

试试这个

DECLARE @table AS TABLE
    (
      ID INT IDENTITY(1, 1) ,
      SomeText VARCHAR(500)
    )
INSERT  INTO @table
        ( SomeText )
VALUES  ( '4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione' ),
        ( '10-Contrassegno' ),
        ( '12-Documenti di annullo polizza-10-Contrassegno' ),
        ( '10-Contrassegno' ),
        ( '12-Documenti di annullo polizza-10-Contrassegno' );
WITH    cte
          AS ( SELECT   n = 1
               UNION ALL
               SELECT   n + 1
               FROM     cte
               WHERE    n <= 100
             ),
        SplitToChr
          AS ( SELECT   T.ID ,
                        SUBSTRING(T.SomeText, cte.n, 1) AS Chr
               FROM     @table AS T
                        JOIN cte ON DATALENGTH(T.SomeText) >= cte.n
                                    AND SUBSTRING(T.SomeText, cte.n, 1) LIKE '[0-9-]'
             )
    SELECT   T.ID ,
            REVERSE(SUBSTRING(REVERSE(T.FInal),2,LEN(T.FInal))) AS Final
    FROM    ( SELECT  DISTINCT
                        o.ID ,
                        REPLACE(( SELECT    '' + chr
                                  FROM      SplitToChr AS i
                                  WHERE     i.id = o.id
                                FOR
                                  XML PATH('')
                                ), '--', '-') AS FInal
              FROM      SplitToChr AS o
            ) AS T

【讨论】:

    【解决方案2】:

    示例表

    CREATE TABLE #TEMP(STRINGCOLUMN NVARCHAR(MAX))
    
    INSERT INTO #TEMP
    SELECT '4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione'
    UNION ALL
    SELECT '10-Contrassegno'
    UNION ALL
    SELECT '12-Documenti di annullo polizza-10-Contrassegno'
    UNION ALL
    SELECT '10-Contrassegno'
    UNION ALL
    SELECT '12-Documenti di annullo polizza-10-Contrassegno'
    

    如果您需要简单的查询,您可以使用函数

    功能

    CREATE FUNCTION [dbo].[ConvertToNumber]
    (@strAlphaNumeric VARCHAR(256))
    RETURNS VARCHAR(256)
    AS
    BEGIN    
    SET @strAlphaNumeric = LEFT(@strAlphaNumeric,
    LEN(@strAlphaNumeric) - CHARINDEX('-', REVERSE(@strAlphaNumeric)) + 0)
    DECLARE @intAlpha INT
    SET @intAlpha = PATINDEX('%[^0-9]-%', @strAlphaNumeric)
    BEGIN
        WHILE @intAlpha > 0
        BEGIN
            SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
            SET @intAlpha = PATINDEX('%[^0-9]-%', @strAlphaNumeric )
        END
    END
    RETURN ISNULL(@strAlphaNumeric,0)
    END
    

    还有你的最终查询

    SELECT DBO.ConvertToNumber(STRINGCOLUMN)STRINGCOLUMN
    FROM #TEMP
    

    结果

    【讨论】:

    • 关于您的最终查询,“ConvertToNumber”是来自 C# 的代码,而不是来自 T-SQL :-)
    • 我没听懂你。 ConvertToNumber 是 C# 中的代码 是什么意思?这里有什么问题吗? @克劳迪奥
    • ConvertToNumber 在 T-SQL 中不存在,我可以看到你在最后的查询部分中写了它:)
    • 这是一个 USER-DEFINED 函数。我认为您没有在 SQL Server 中使用过函数。 SQL Server 支持像 C# 这样的函数,我们调用函数将参数传递给函数以获得所需的输出。 @克劳迪奥
    • 当然,我在 SQL Server 中使用过 UDF……但我从来不用,也不知道您可以在其中使用 C# 代码!!! :-) @Sarath Avanavu
    【解决方案3】:

    首先使用这个拆分函数

    CREATE FUNCTION [dbo].[fnSplitString] ( @string NVARCHAR(MAX)
    ,                                       @delimiter CHAR(1) )
    RETURNS @output TABLE ( splitdata NVARCHAR(MAX) )
    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
    

    然后使用这段代码

    CREATE TABLE #t10 ( id  int identity(1,1)
    ,                   num int )
    INSERT INTO #t10
    select *
    from dbo.fnSplitString ('4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione','-')
    WHERE ISNUMERIC(splitdata)=1
    DECLARE @x int = 1
    DECLARE @y varchar(10)=''
    DECLARE @q varchar(10)
    WHILE @x<=(SELECT count(*)
        from #t10)
    BEGIN
        SET @q=(SELECT num
        FROM #t10
        WHERE id = @x )
        set @y=@y+@q+'-'
        SET @x=@x+1
    END
    SELECT left(ltrim(@y),len(@y)-1)
    --SELECT * FROM #t10
    --drop table #t10
    

    【讨论】:

    • 在 sql 中分割字符串的所有可能方法中,while 循环是性能最差的方法。我建议将您的功能更改为任何更快的选项。 sqlperformance.com/2012/07/t-sql-queries/split-strings
    • 好吧,你说任何 - 我检查我的拆分器与 '[dbo].[SplitStrings_CTE]' 和执行计划看起来一样。
    • 如果您可以使用已被证明比其他代码慢的代码,那对我来说没问题。是你的系统因为不是我的而变慢了。 :)
    【解决方案4】:

    这有点乱,但它完成了工作:-)

                CREATE TABLE dbo.Documents (
                Details VARCHAR(1000)
                );
    
    
                GO
    
                INSERT INTO dbo.Documents
                VALUES ('4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione'),
                       ('10-Contrassegno'),
                       ('12-Documenti di annullo polizza-10-Contrassegno'),
                       ('10-Contrassegno'),
                       ('12-Documenti di annullo polizza-10-Contrassegno');
    
    
    
                 SELECT CASE WHEN (FirstLine + SecondLine +  ThirdLine) LIKE '%-' 
                        THEN LEFT(FirstLine + SecondLine +  ThirdLine, LEN(FirstLine + SecondLine +  ThirdLine) -1)
                        ELSE (FirstLine + SecondLine +  ThirdLine) END AS CleanData
                 FROM (  
    
                   SELECT 
                    LEFT(Details, CHARINDEX('-', Details)) AS FirstLine,
                 REPLACE(CASE 
                            WHEN REPLACE(  REPLACE( LEFT(Details,CHARINDEX('-', Details, CHARINDEX('-', Details )+1)+2)     ,    LEFT(Details, CHARINDEX('-', Details, CHARINDEX('-', Details)+1)),    ''), LEFT(Details, CHARINDEX('-', Details)),  '') LIKE '%[0-9]' THEN   REPLACE(  REPLACE( LEFT(Details,CHARINDEX('-', Details, CHARINDEX('-', Details )+1)+2)     ,    LEFT(Details, CHARINDEX('-', Details, CHARINDEX('-', Details)+1)),    ''), LEFT(Details, CHARINDEX('-', Details)),  '') + '-'
                   ELSE  REPLACE( LEFT(Details,CHARINDEX('-', Details, CHARINDEX('-', Details )+1)+2)     ,    LEFT(Details, CHARINDEX('-', Details, CHARINDEX('-', Details)+1)),    '')
                   END , LEFT(Details, CHARINDEX('-', Details)),  '') AS SecondLine,
                   CASE  WHEN REVERSE(LEFT(REVERSE(Details), CHARINDEX('-', REVERSE(Details))+2)) LIKE '-%'
                    THEN LEFT(REVERSE(LEFT(REVERSE(Details), CHARINDEX('-', REVERSE(Details))+2)), 3) ELSE '' END  AS ThirdLine
                   FROM dbo.Documents 
                   ) AS A;
    

    【讨论】:

      【解决方案5】:

      另一种更简单的方法。创建一个function 以从字符串中删除alphabets

      Create FUNCTION dbo.RemoveAlphabets (@string VARCHAR(256))
      returns VARCHAR(256)
        BEGIN
            IF @string  IS NULL
              RETURN NULL
      
            DECLARE @Result VARCHAR(256)='',@len INT = Len(@string ),@cnt INT=1
      
            WHILE @cnt <= @len
              BEGIN
                  DECLARE @parse INT
                  SET @parse = Ascii(Substring(@string , @cnt, 1))
      
                  IF @parse BETWEEN 48 AND 57 or @parse =45
                   SET @Result =  @Result + Char(@parse) 
      
                  SET @cnt = @cnt + 1
              END
              select @result= replace(@Result,'--','-')
            RETURN left(@result,case when right(@Result,1)='-' then len(@Result)-1 else len(@result) end) 
        END 
      

      如果字符串中的数字总是被'-'包围,那么用这个替换return 语句。

       RETURN left(@result,len(@Result)-1) 
      

      执行函数

      select dbo.RemoveAlphabets
      ('4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione')
      

      结果4-3-2

      【讨论】:

        猜你喜欢
        • 2020-12-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 2013-03-12
        • 2021-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多