【问题标题】:SQL - SUBSTRING and CHARINDEX [duplicate]SQL - SUBSTRING 和 CHARINDEX [重复]
【发布时间】:2012-11-15 09:45:50
【问题描述】:

可能重复:
T-SQL: Opposite to string concatenation - how to split string into multiple records
Splitting variable length delimited string across multiple rows (SQL)

我有一个包含如下列数据的数据库表:

Data (field name)
1111,44,666,77
22,55,76,54
32,31,56

我意识到这是一个非常糟糕的设计,因为它没有标准化(我没有设计它 - 我继承了它)。是否有一个查询会返回这样的数据:

1111
44
666
77
22
55
76
54
32
31
56

我习惯使用 CHARINDEX 和 SUBSTRING,但我想不出一种方法,因为每个单元格中的元素数量(由逗号分隔)是未知的。

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:
    SELECT REPLACE(field_name, ',', ' ') from table
    

    编辑:当你改变你的问题时,不要介意这个答案。

    【讨论】:

    • 我更改了问题的格式以使其更清晰。对此感到抱歉。
    【解决方案2】:

    不谈性能,你可以将数据串联成一列,然后拆分。

    连接数据:http://sqlfiddle.com/#!6/487a4/3

    拆分:T-SQL: Opposite to string concatenation - how to split string into multiple records

    【讨论】:

      【解决方案3】:

      查看类似问题中引用的这篇文章:

      http://www.codeproject.com/Articles/7938/SQL-User-Defined-Function-to-Parse-a-Delimited-Str

      如果您创建他们在那篇文章中的函数,您可以使用以下方法调用它:

      select * from dbo.fn_ParseText2Table('100|120|130.56|Yes|Cobalt Blue','|')

      【讨论】:

      • SQL Server 可以APPLY 表值函数...不需要游标!哎呀!
      • 不知道我这么说的时候在想什么。我的错!
      【解决方案4】:

      我创建了一个名为 [dbo].[stack] 的表,并用您提供的数据填充它,这个脚本产生了您需要的数据。可能有一种更有效的方法来执行此操作,但这完全符合您的要求。

          BEGIN
              DECLARE @tmp TABLE (data VARCHAR(20))
              DECLARE @tmp2 TABLE (data VARCHAR(20))
      
              --Insert all fields from your table
              INSERT INTO @tmp (data)
              SELECT [data]           
              FROM   [dbo].[stack] -- your table name here
      
              --Loop through all the records in temp table
              WHILE EXISTS (SELECT 1
                                          FROM   @tmp)            
                  BEGIN 
                      DECLARE @data VARCHAR(100) --Variable to chop up 
                      DECLARE @data1 VARCHAR(100) -- Untouched variable to delete from tmp table
                      SET @data =  (SELECT TOP 1 [data]
                                                  FROM   @tmp)
                      SET @data1 =  (SELECT TOP 1 [data]
                                                   FROM   @tmp)
      
                      --Loop through variable to get individual value 
                      WHILE PATINDEX('%,%',@data) > 0     
                          BEGIN
                              INSERT INTO @tmp2
                              SELECT SUBSTRING(@data,1,PATINDEX('%,%',@data)-1);
                              SET @data = SUBSTRING(@data,PATINDEX('%,%',@data)+1,LEN(@data))
                              IF PATINDEX('%,%',@data) = 0
                                  INSERT INTO @tmp2
                                  SELECT @data            
                          END
      
                      DELETE FROM @tmp 
                      WHERE [data] = @data1
      
                  END     
      
              SELECT * FROM @tmp2     
          END
      

      【讨论】:

        【解决方案5】:

        您可以使用 CTE 来拆分数据:

        ;with cte (DataItem, Data) as
        (
          select cast(left(Data, charindex(',',Data+',')-1) as varchar(50)) DataItem,
                 stuff(Data, 1, charindex(',',Data+','), '') Data
          from yourtable
          union all
          select cast(left(Data, charindex(',',Data+',')-1) as varchar(50)) DataItem,
            stuff(Data, 1, charindex(',',Data+','), '') Data
          from cte
          where Data > ''
        ) 
        select DataItem
        from cte
        

        SQL Fiddle with Demo

        结果:

        | DATAITEM |
        ------------
        |     1111 |
        |       22 |
        |       32 |
        |       31 |
        |       56 |
        |       55 |
        |       76 |
        |       54 |
        |       44 |
        |      666 |
        |       77 |
        

        或者你可以创建一个拆分函数:

        create FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))       
        returns @temptable TABLE (items varchar(MAX))       
        as       
        begin      
            declare @idx int       
            declare @slice varchar(8000)       
        
            select @idx = 1       
                if len(@String)<1 or @String is null  return       
        
            while @idx!= 0       
            begin       
                set @idx = charindex(@Delimiter,@String)       
                if @idx!=0       
                    set @slice = left(@String,@idx - 1)       
                else       
                    set @slice = @String       
        
                if(len(@slice)>0)  
                    insert into @temptable(Items) values(@slice)       
        
                set @String = right(@String,len(@String) - @idx)       
                if len(@String) = 0 break       
            end   
        return 
        end;
        

        您可以在查询时使用它,这将产生相同的结果:

        select s.items declaration
        from yourtable t1
        outer apply dbo.split(t1.data, ',') s
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-07-28
          • 1970-01-01
          • 1970-01-01
          • 2019-08-19
          • 2012-02-24
          • 2013-05-29
          • 2023-03-10
          • 1970-01-01
          相关资源
          最近更新 更多