如何在多列中拆分列值

时间:2013-11-11 04:01:06

标签: sql-server

你能告诉我吗? 如何划分

ID     SN    Types
1      123   ABC,XYZ,TEST, RJK,CDF,TTT,UMB,UVX
2      234   RJK,CDF,TTT,UMB,UVX,TTT,UMB,UVX
3      345   OID,XYZ,TTT,UMB,UVX,TTT,UMB,UVX

作为

 ID     SN    Types1  Types2  Types3  Types4  Types5  Types6  Types7  Types8
 1      123   ABC       XYZ    TEST     RJK    CDF     TTT     UMB     UVX  
 2      234   RJK       CDF    TTT      UMB    UVX     TTT     UMB     UVX 
 3      345   OID       XYZ    TTT      UMB    UVX     TTT     UMB     UVX 

请发给我sqlcode 感谢,

2 个答案:

答案 0 :(得分:2)

首先,创建一个维护顺序的拆分功能:

CREATE FUNCTION [dbo].[SplitStrings_Ordered]
(
    @List       NVARCHAR(MAX),
    @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
AS
    RETURN (SELECT [Index] = ROW_NUMBER() OVER (ORDER BY Number), Item 
    FROM (SELECT Number, Item = SUBSTRING(@List, Number, 
      CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)
     FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
      FROM sys.all_objects) AS n(Number)
      WHERE Number <= CONVERT(INT, LEN(@List))
      AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
    ) AS y);

现在,您可以将此功能与PIVOT结合使用。这是一个自我封闭的示例,但您可以将最后一个查询中的@d替换为您的真实表格。

DECLARE @d TABLE(ID INT, SN INT, Types NVARCHAR(MAX));

INSERT @d VALUES
(1,123,N'ABC,XYZ,TEST, RJK,CDF,TTT,UMB,UVX'),
(2,234,N'RJK,CDF,TTT,UMB,UVX,TTT,UMB,UVX'  ),
(3,345,N'OID,XYZ,TTT,UMB,UVX,TTT,UMB,UVX'  );

SELECT ID,SN,
 Types1 = [1], Types2 = [2], Types3 = [3], Types4 = [4],
 Types1 = [5], Types6 = [6], Types7 = [7], Types8 = [8]
FROM @d AS d CROSS APPLY dbo.SplitStrings_Ordered(d.Types, ',') AS y
PIVOT (MAX(Item) FOR [Index] IN ([1],[2],[3],[4],[5],[6],[7],[8])) AS p;

答案 1 :(得分:0)

T-SQL不适合处理以逗号分隔的值。但是,通过创造性地使用Recursive CTE,可以毫不费力地拆分列。以下查询假设原始数据中一行中总共不超过8种类型 - 可以简单地扩展以处理任意数量的类型(尽管不是动态的,必须知道最大数量):

;with TypesSplit as (

    select [ID], [SN], 1 as [Index],
    case when CHARINDEX(',', [Types]) <> 0 then substring([Types], CHARINDEX(',', [Types])+1, 1000) else '' end as [Types],
    case when CHARINDEX(',', [Types]) <> 0 then substring([Types], 1, CHARINDEX(',', [Types])-1) else [Types] end as [Type]
    from Types

    union all

    select [ID], [SN], [Index] + 1 as [Index],
    case when CHARINDEX(',', [Types]) <> 0 then substring([Types], CHARINDEX(',', [Types])+1, 1000) else '' end as [Types],
    case when CHARINDEX(',', [Types]) <> 0 then substring([Types], 1, CHARINDEX(',', [Types])-1) else [Types] end as [Type]
    from TypesSplit
    where LEN([Types])>0

)
select [ID],[SN],
    max(case when [Index]=1 then [Type] end) as Types1,
    max(case when [Index]=2 then [Type] end) as Types2,
    max(case when [Index]=3 then [Type] end) as Types3,
    max(case when [Index]=4 then [Type] end) as Types4,
    max(case when [Index]=5 then [Type] end) as Types5,
    max(case when [Index]=6 then [Type] end) as Types6,
    max(case when [Index]=7 then [Type] end) as Types7,
    max(case when [Index]=8 then [Type] end) as Types8
from TypesSplit
group by [ID],[SN]

(演示:http://www.sqlfiddle.com/#!6/c522f/9

基本思路是使用CHARINDEX查找每个逗号的位置,然后SUBSTRING从头开始分割每种类型。递归循环遍历所有类型,直到没有剩余的消费。类型通过[Index]列编号,以允许在输出中以相同的顺序再现它们。输出基本上是递归CTE生成的行数据的数据透视表,在旋转之前看起来像这样:

| ID |  SN | INDEX |                        TYPES | TYPE |
|----|-----|-------|------------------------------|------|
|  1 | 123 |     1 | XYZ,TEST,RJK,CDF,TTT,UMB,UVX |  ABC |
|  2 | 234 |     1 |  CDF,TTT,UMB,UVX,TTT,UMB,UVX |  RJK |
|  3 | 345 |     1 |  XYZ,TTT,UMB,UVX,TTT,UMB,UVX |  OID |
|  3 | 345 |     2 |      TTT,UMB,UVX,TTT,UMB,UVX |  XYZ |
|  3 | 345 |     3 |          UMB,UVX,TTT,UMB,UVX |  TTT |
|  3 | 345 |     4 |              UVX,TTT,UMB,UVX |  UMB |
|  3 | 345 |     5 |                  TTT,UMB,UVX |  UVX |
|  3 | 345 |     6 |                      UMB,UVX |  TTT |
|  3 | 345 |     7 |                          UVX |  UMB |
|  3 | 345 |     8 |                              |  UVX |
|  2 | 234 |     2 |      TTT,UMB,UVX,TTT,UMB,UVX |  CDF |
|  2 | 234 |     3 |          UMB,UVX,TTT,UMB,UVX |  TTT |
|  2 | 234 |     4 |              UVX,TTT,UMB,UVX |  UMB |
|  2 | 234 |     5 |                  TTT,UMB,UVX |  UVX |
|  2 | 234 |     6 |                      UMB,UVX |  TTT |
|  2 | 234 |     7 |                          UVX |  UMB |
|  2 | 234 |     8 |                              |  UVX |
|  1 | 123 |     2 |     TEST,RJK,CDF,TTT,UMB,UVX |  XYZ |
|  1 | 123 |     3 |          RJK,CDF,TTT,UMB,UVX | TEST |
|  1 | 123 |     4 |              CDF,TTT,UMB,UVX |  RJK |
|  1 | 123 |     5 |                  TTT,UMB,UVX |  CDF |
|  1 | 123 |     6 |                      UMB,UVX |  TTT |
|  1 | 123 |     7 |                          UVX |  UMB |
|  1 | 123 |     8 |                              |  UVX |

旋转后,最终输出如下:

| ID |  SN | TYPES1 | TYPES2 | TYPES3 | TYPES4 | TYPES5 | TYPES6 | TYPES7 | TYPES8 |
|----|-----|--------|--------|--------|--------|--------|--------|--------|--------|
|  1 | 123 |    ABC |    XYZ |   TEST |    RJK |    CDF |    TTT |    UMB |    UVX |
|  2 | 234 |    RJK |    CDF |    TTT |    UMB |    UVX |    TTT |    UMB |    UVX |
|  3 | 345 |    OID |    XYZ |    TTT |    UMB |    UVX |    TTT |    UMB |    UVX |