将1列的值拆分为3个单独的列

时间:2020-07-17 17:01:51

标签: sql sql-server

我在SQL Server 2008 R2中有以下查询:

SELECT  
    Item.item,
    (CASE 
        WHEN item.item LIKE 'RC-%' THEN 'Rectangle'
        WHEN item.item LIKE 'T-%' THEN 'PIPE'
        WHEN item.item LIKE 'B-%' THEN 'BAR'
     END) as PROD_TYPE
FROM 
    item
WHERE 
    item.item LIKE 'RC-%' OR 
    item.item LIKE 'T-%' OR 
    item.item LIKE 'B-%'

产生此数据集:

item            PROD_TYPE
=========================
B-10.000-XM12   BAR
B-1045-10.000   BAR
B-1045-10.500   BAR
B-1045-12.000   BAR

我需要将item列分成3个单独的列,这样看起来像这样:

item            PROD_TYPE   col1  col2       col3
===================================================
B-10.000-XM12   BAR         B     10.000     XM12
B-1045-10.000   BAR         B     1045       10.000
B-1045-10.500   BAR         B     1045       10.500
B-1045-12.000   BAR         B     1045       12.000

我尝试了以下查询:

SELECT  
    Item.item,
    SUBSTRING (Item.item, 1, CHARINDEX('-', Item.item) - 1) col1,
    SUBSTRING (Item.item, CHARINDEX ('-', Item.item) + 1, LEN(Item.item)) col2,
    REVERSE (PARSENAME(REPLACE(REVERSE(REPLACE(Item.item,'.','/')), '-', '.'), 3)) as col3,
    (CASE 
        WHEN item.item LIKE 'RC-%' THEN 'Rectangle'
        WHEN item.item LIKE 'T-%' THEN 'PIPE'
        WHEN item.item LIKE 'B-%' THEN 'BAR'
     END) as PROD_TYPE
FROM 
    item
WHERE 
    item.item LIKE 'RC-%' OR 
    item.item LIKE 'T-%' OR 
    item.item LIKE 'B-%'

,该查询返回以下结果:

item            col1   col2         col3    PRO_TYPE
----------------------------------------------------
B-10.000-XM12   B      10.000-XM12  XM12    BAR
B-1045-10.000   B      1045-10.000  10/000  BAR
B-1045-10.500   B      1045-10.500  10/500  BAR

我只是想不通如何获取项目数据中最后一部分的破折号的下一个索引。

有想法吗?

4 个答案:

答案 0 :(得分:1)

SQL Server具有糟糕的字符串拆分功能(提示,提示:数据库不是进行这些转换的最佳位置)。

我发现带有字符串函数的cross apply是解决这些问题的最佳方法:

with items as (
      select 'B-10.000-XM12' as item union all
      select 'B-1045-10.000' as item union all
      select 'B-1045-10.500' as item union all
      select 'B-1045-12.000' as item 
     )
select *,
       (CASE WHEN i.item LIKE 'RC-%' THEN 'Rectangle'
             WHEN i.item LIKE 'T-%' THEN 'PIPE'
             WHEN i.item LIKE 'B-%' THEN 'BAR'
        END) as PROD_TYPE,
       v1.col, v2.col, v2.rest
from items i cross apply
     (values (left(i.item, charindex('-', i.item) - 1),
              stuff(i.item, 1, charindex('-', i.item), ''))
     ) v1(col, rest) cross apply
     (values (left(v1.rest, charindex('-', v1.rest) - 1),
              stuff(v1.rest, 1, charindex('-', v1.rest), ''))
     ) v2(col, rest);

Here是db <>小提琴。

答案 1 :(得分:1)

另一个选择

Declare @YourTable Table ([item] varchar(50),[PROD_TYPE] varchar(50))
Insert Into @YourTable Values 
 ('B-10.000-XM12','BAR')
,('B-1045-10.000','BAR')
,('B-1045-10.500','BAR')
,('B-1045-12.000','BAR')
 
Select A.*
      ,B.*
 From @YourTable A
 Cross Apply (
                Select Pos1 = xDim.value('/x[1]','varchar(100)')
                      ,Pos2 = xDim.value('/x[2]','varchar(100)')
                      ,Pos3 = xDim.value('/x[3]','varchar(100)')
                From  ( values (cast('<x>' + replace([item],'-','</x><x>')+'</x>' as xml))) A(xDim) 
             ) B

返回

item            PROD_TYPE   Pos1    Pos2    Pos3
B-10.000-XM12   BAR         B       10.000  XM12
B-1045-10.000   BAR         B       1045    10.000
B-1045-10.500   BAR         B       1045    10.500
B-1045-12.000   BAR         B       1045    12.000

答案 2 :(得分:0)

交叉应用使表达式嵌套看起来很整洁:

select      Item.item,
            prod_type = case 
                            WHEN item.item like 'RC-%' THEN 'Rectangle'
                            WHEN item.item like 'T-%' THEN 'PIPE'
                            WHEN item.item like 'B-%' THEN 'BAR'
                        end,
            col1      = left(item, h1.pos - 1),
            col2      = substring(item, h1.pos + 1, h2.pos - h1.pos - 1),
            col3      = right(item, len(item) - h2.pos)

from        item
cross apply (select charindex('-', item)) h1(pos)
cross apply (select charindex('-', item, h1.pos + 1)) h2(pos)
where       item.item like 'RC-%' 
or          item.item LIKE 'T-%' 
or          item.item LIKE 'B-%'

答案 3 :(得分:0)

其他答案中列出了多个选项-正如我之前评论的那样-此https://datamajor.net/mssqlsplitcolumn/

中列出了您的方案的详细说明

已经发布了几个选项作为答案,并列出了剩下的选项-

create Table tabl ([item] varchar(50),[PROD_TYPE] varchar(50));
Insert Into tabl Values 
 ('B-10.000-XM12','BAR')
,('B-1045-10.000','BAR')
,('B-1045-10.500','BAR')
,('B-1045-12.000','BAR');

方法1. String_Split

WITH C AS(
SELECT ITEM
      ,value 
      ,ROW_NUMBER() OVER(PARTITION BY ITEM ORDER BY (SELECT NULL)) as rn
FROM tabl BO
    CROSS APPLY STRING_SPLIT(ITEM, '-') AS BK
)
SELECT ITEM
      ,[1] AS COL1
      ,[2] AS COl2
      ,[3] AS COL3
FROM C
PIVOT(
    MAX(VALUE)
    FOR RN IN([1],[2],[3])  
) as PVT ;

使用功能

CREATE FUNCTION dbo.GetColumnValue(
    @String VARCHAR(MAX),
    @Delimiter CHAR(1),
    @Column INT = 1
)
RETURNS VARCHAR(MAX)
AS    
BEGIN
DECLARE @idx INT
DECLARE @slice VARChar(MAX)     
SELECT @idx = 1     
    IF LEN(@String)<1 OR @String IS NULL
        RETURN NULL
DECLARE @ColCnt INT
    SET @ColCnt = 1
WHILE (@idx != 0)
BEGIN    
    SET @idx = CHARINDEX(@Delimiter,@String)     
    IF @idx!=0 
    BEGIN
        IF (@ColCnt = @Column) 
            RETURN LEFT(@String,@idx - 1)        
        SET @ColCnt = @ColCnt + 1
    END
    SET @String = RIGHT(@String,LEN(@String) - @idx)     
    IF LEN(@String) = 0 BREAK
END
RETURN @String  
END 
;

SELECT
    ITEM ,
    dbo.GetColumnValue(ITEM, '-', 1) as PRODUCTID 
        ,dbo.GetColumnValue(ITEM, '-', 2) as NAME
        ,dbo.GetColumnValue(ITEM, '-', 3) as PAGES

FROM TABL