SQL - SUBSTRING和CHARINDEX

时间:2012-11-27 17:35:50

标签: sql sql-server

  

可能重复:
  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,但我想不出这样做的方法,因为每个单元格中的元素数量(以逗号分隔)是未知的。

5 个答案:

答案 0 :(得分:2)

我创建了一个名为[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

答案 1 :(得分:2)

您可以使用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

答案 2 :(得分:0)

SELECT REPLACE(field_name, ',', ' ') from table

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

答案 3 :(得分:0)

不谈论性能,您可以将数据连接在一个列中,然后将其拆分。

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

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

答案 4 :(得分:0)

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

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','|')